Browse Source

Merge remote-tracking branch 'upstream/develop' into evmjit_stack

cl-refactor
Paweł Bylica 10 years ago
parent
commit
2bd892c1fc
  1. 61
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 70
      eth/main.cpp
  4. 6
      ethminer/MinerAux.h
  5. 15
      exp/main.cpp
  6. 2
      libdevcore/Common.cpp
  7. 2
      libdevcore/Exceptions.h
  8. 2
      libdevcore/TrieDB.h
  9. 10
      libdevcrypto/Common.cpp
  10. 2
      libdevcrypto/CryptoPP.cpp
  11. 18
      libethcore/BlockInfo.cpp
  12. 1
      libethcore/BlockInfo.h
  13. 17
      libethcore/Common.cpp
  14. 4
      libethcore/Common.h
  15. 4
      libethcore/EthashSealEngine.cpp
  16. 2
      libethcore/Miner.h
  17. 14
      libethcore/Params.cpp
  18. 15
      libethcore/Params.h
  19. 2
      libethcore/Sealer.h
  20. 34
      libethereum/BlockChain.cpp
  21. 21
      libethereum/BlockChain.h
  22. 54
      libethereum/CanonBlockChain.cpp
  23. 15
      libethereum/CanonBlockChain.h
  24. 31
      libethereum/Client.cpp
  25. 51
      libethereum/Client.h
  26. 34
      libethereum/GenesisInfo.cpp
  27. 1
      libethereum/State.h
  28. 2
      libwebthree/WebThree.cpp
  29. 2
      mix/QBigInt.h
  30. 2
      mix/QFunctionDefinition.h
  31. 1
      mix/qml/Block.qml
  32. 54
      mix/qml/BlockChain.qml
  33. 198
      mix/qml/DeployContractStep.qml
  34. 21
      mix/qml/DeploymentDialog.qml
  35. 170
      mix/qml/DeploymentDialogSteps.qml
  36. 6
      mix/qml/DeploymentWorker.qml
  37. 55
      mix/qml/KeyValuePanel.qml
  38. 2
      mix/qml/PackagingStep.qml
  39. 20
      mix/qml/ProjectModel.qml
  40. 74
      mix/qml/RegisteringStep.qml
  41. 4
      mix/qml/ScenarioLoader.qml
  42. 2
      mix/qml/StatusPane.qml
  43. 3
      mix/qml/WebPreview.qml
  44. 39
      mix/qml/js/NetworkDeployment.js
  45. 3
      mix/qml/js/TransactionHelper.js
  46. 46
      test/libsolidity/SolidityWallet.cpp

61
alethzero/MainWin.cpp

@ -189,6 +189,9 @@ Main::Main(QWidget *parent) :
#endif #endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
if (!dev::contents(getDataDir() + "/genesis.json").empty())
CanonBlockChain<Ethash>::setGenesis(contentsString(getDataDir() + "/genesis.json"));
cerr << "State root: " << CanonBlockChain<Ethash>::genesis().stateRoot() << endl; cerr << "State root: " << CanonBlockChain<Ethash>::genesis().stateRoot() << endl;
auto block = CanonBlockChain<Ethash>::createGenesisBlock(); auto block = CanonBlockChain<Ethash>::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain<Ethash>::genesis().hash() << endl; cerr << "Block Hash: " << CanonBlockChain<Ethash>::genesis().hash() << endl;
@ -375,10 +378,17 @@ NetworkPreferences Main::netPrefs() const
publicIP.clear(); publicIP.clear();
} }
NetworkPreferences ret;
if (isPublicAddress(publicIP)) if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked()); ret = NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
else else
return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked()); ret = NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked());
ret.discovery = m_privateChain.isEmpty();
ret.pin = m_privateChain.isEmpty();
return ret;
} }
void Main::onKeysChanged() void Main::onKeysChanged()
@ -773,6 +783,30 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
void Main::setPrivateChain(QString const& _private, bool _forceConfigure)
{
if (m_privateChain == _private && !_forceConfigure)
return;
m_privateChain = _private;
ui->usePrivate->setChecked(!m_privateChain.isEmpty());
CanonBlockChain<Ethash>::forceGenesisExtraData(m_privateChain.isEmpty() ? bytes() : sha3(m_privateChain.toStdString()).asBytes());
// rejig blockchain now.
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
web3()->setNetworkPreferences(netPrefs());
ethereum()->reopenChain();
readSettings(true);
installWatches();
refreshAll();
}
Secret Main::retrieveSecret(Address const& _address) const Secret Main::retrieveSecret(Address const& _address) const
{ {
while (true) while (true)
@ -849,8 +883,7 @@ void Main::readSettings(bool _skipGeometry)
ui->listenIP->setText(s.value("listenIP", "").toString()); ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString()); ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString(); setPrivateChain(s.value("privateChain", "").toString());
ui->usePrivate->setChecked(m_privateChain.size());
ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->verbosity->setValue(s.value("verbosity", 1).toInt());
#if ETH_EVMJIT // We care only if JIT is enabled. Otherwise it can cause misconfiguration. #if ETH_EVMJIT // We care only if JIT is enabled. Otherwise it can cause misconfiguration.
@ -1033,21 +1066,15 @@ void Main::on_exportState_triggered()
void Main::on_usePrivate_triggered() void Main::on_usePrivate_triggered()
{ {
QString pc;
if (ui->usePrivate->isChecked()) if (ui->usePrivate->isChecked())
{ {
m_privateChain = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0))); bool ok;
if (m_privateChain.isEmpty()) pc = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)), &ok);
{ if (!ok)
if (ui->usePrivate->isChecked()) return;
ui->usePrivate->setChecked(false);
else
// was cancelled.
return;
}
} }
else setPrivateChain(pc);
m_privateChain.clear();
on_killBlockchain_triggered();
} }
void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); } void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); }
@ -2012,7 +2039,7 @@ void Main::on_net_triggered()
{ {
web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); ethereum()->setNetworkId((h256)(u256)(int)c_network);
web3()->startNetwork(); web3()->startNetwork();
ui->downloadView->setEthereum(ethereum()); ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode())); ui->enode->setText(QString::fromStdString(web3()->enode()));

2
alethzero/MainWin.h

@ -226,6 +226,8 @@ private:
void readSettings(bool _skipGeometry = false); void readSettings(bool _skipGeometry = false);
void writeSettings(); void writeSettings();
void setPrivateChain(QString const& _private, bool _forceConfigure = false);
unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f);
unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); unsigned installWatch(dev::h256 _tf, WatchHandler const& _f);
void uninstallWatch(unsigned _w); void uninstallWatch(unsigned _w);

70
eth/main.cpp

@ -121,8 +121,13 @@ void help()
<< "Usage eth [OPTIONS]" << endl << "Usage eth [OPTIONS]" << endl
<< "Options:" << endl << endl << "Options:" << endl << endl
<< "Client mode (default):" << endl << "Client mode (default):" << endl
<< " --olympic Use the Olympic (0.9) protocol." << endl
<< " --frontier Use the Frontier (1.0) protocol." << endl
<< " --private <name> Use a private chain." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (default: full)." << endl << " -o,--mode <full/peer> Start a full node or a peer node (default: full)." << endl
#if ETH_JSCONSOLE || !ETH_TRUE
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#endif
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port <n> Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl << " --json-rpc-port <n> Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
@ -139,7 +144,6 @@ void help()
<< " --master <password> Give the master password for the key store." << endl << " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl << " --password <password> Give a password for a private key." << endl
<< " --sentinel <server> Set the sentinel for reporting bad blocks or chain issues." << endl << " --sentinel <server> Set the sentinel for reporting bad blocks or chain issues." << endl
<< " --prime <n> Specify n as the 6 digit prime number to start Frontier." << endl
<< endl << endl
<< "Client transacting:" << endl << "Client transacting:" << endl
/*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl /*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
@ -168,10 +172,10 @@ void help()
<< " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl << " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl << " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl
<< " --port <port> Connect to remote port (default: 30303)." << endl << " --port <port> Connect to remote port (default: 30303)." << endl
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl << " --network-id <n> Only connect to other hosts with this network id." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
<< " --no-discovery Disable Node discovery. (experimental)" << endl << " --no-discovery Disable Node discovery." << endl
<< " --pin Only connect to required (trusted) peers. (experimental)" << endl << " --pin Only connect to required (trusted) peers." << endl
// << " --require-peers <peers.json> List of required (trusted) peers. (experimental)" << endl // << " --require-peers <peers.json> List of required (trusted) peers. (experimental)" << endl
<< endl; << endl;
MinerCLI::streamHelp(cout); MinerCLI::streamHelp(cout);
@ -196,9 +200,6 @@ void help()
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
#if ETH_JSCONSOLE || !ETH_TRUE
<< " --console Use interactive javascript console" << endl
#endif
; ;
exit(0); exit(0);
} }
@ -1068,8 +1069,8 @@ int main(int argc, char** argv)
/// Operating mode. /// Operating mode.
OperationMode mode = OperationMode::Node; OperationMode mode = OperationMode::Node;
string dbPath; string dbPath;
unsigned prime = 0; // unsigned prime = 0;
bool yesIReallyKnowWhatImDoing = false; // bool yesIReallyKnowWhatImDoing = false;
/// File name for import/export. /// File name for import/export.
string filename; string filename;
@ -1083,10 +1084,14 @@ int main(int argc, char** argv)
/// General params for Node operation /// General params for Node operation
NodeMode nodeMode = NodeMode::Full; NodeMode nodeMode = NodeMode::Full;
bool interactive = false; bool interactive = false;
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
int jsonrpc = -1; int jsonrpc = -1;
#endif #endif
string jsonAdmin; string jsonAdmin;
string genesisJSON;
dev::eth::Network releaseNetwork = c_network;
string privateChain;
bool upnp = true; bool upnp = true;
WithExisting withExisting = WithExisting::Trust; WithExisting withExisting = WithExisting::Trust;
string sentinel; string sentinel;
@ -1192,7 +1197,7 @@ int main(int argc, char** argv)
mode = OperationMode::Export; mode = OperationMode::Export;
filename = argv[++i]; filename = argv[++i];
} }
else if (arg == "--prime" && i + 1 < argc) /* else if (arg == "--prime" && i + 1 < argc)
try try
{ {
prime = stoi(argv[++i]); prime = stoi(argv[++i]);
@ -1204,7 +1209,7 @@ int main(int argc, char** argv)
} }
else if (arg == "--yes-i-really-know-what-im-doing") else if (arg == "--yes-i-really-know-what-im-doing")
yesIReallyKnowWhatImDoing = true; yesIReallyKnowWhatImDoing = true;
else if (arg == "--sentinel" && i + 1 < argc) */ else if (arg == "--sentinel" && i + 1 < argc)
sentinel = argv[++i]; sentinel = argv[++i];
else if (arg == "--mine-on-wrong-chain") else if (arg == "--mine-on-wrong-chain")
mineOnWrongChain = true; mineOnWrongChain = true;
@ -1253,6 +1258,15 @@ int main(int argc, char** argv)
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1; return -1;
} }
else if (arg == "--private" && i + 1 < argc)
try {
privateChain = argv[++i];
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill") else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
withExisting = WithExisting::Kill; withExisting = WithExisting::Kill;
else if (arg == "-R" || arg == "--rebuild") else if (arg == "-R" || arg == "--rebuild")
@ -1306,11 +1320,11 @@ int main(int argc, char** argv)
} }
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i]; dbPath = argv[++i];
else if (arg == "--genesis-nonce" && i + 1 < argc) else if (arg == "--genesis-json" && i + 1 < argc)
{ {
try try
{ {
CanonBlockChain<Ethash>::setGenesisNonce(Nonce(argv[++i])); genesisJSON = contentsString(argv[++i]);
} }
catch (...) catch (...)
{ {
@ -1318,6 +1332,10 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "--frontier")
releaseNetwork = eth::Network::Frontier;
else if (arg == "--olympic")
releaseNetwork = eth::Network::Olympic;
/* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) /* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{ {
try try
@ -1412,9 +1430,9 @@ int main(int argc, char** argv)
pinning = true; pinning = true;
else if (arg == "-f" || arg == "--force-mining") else if (arg == "-f" || arg == "--force-mining")
forceMining = true; forceMining = true;
else if (arg == "-i" || arg == "--interactive") else if (arg == "--old-interactive")
interactive = true; interactive = true;
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
else if ((arg == "-j" || arg == "--json-rpc")) else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc; jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc) else if (arg == "--json-rpc-port" && i + 1 < argc)
@ -1422,8 +1440,8 @@ int main(int argc, char** argv)
else if (arg == "--json-admin" && i + 1 < argc) else if (arg == "--json-admin" && i + 1 < argc)
jsonAdmin = argv[++i]; jsonAdmin = argv[++i];
#endif #endif
#if ETH_JSCONSOLE #if ETH_JSCONSOLE || !ETH_TRUE
else if (arg == "--console") else if (arg == "-i" || arg == "--interactive" || arg == "--console")
useConsole = true; useConsole = true;
#endif #endif
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
@ -1471,6 +1489,13 @@ int main(int argc, char** argv)
} }
} }
// Set up all the chain config stuff.
resetNetwork(releaseNetwork);
if (!privateChain.empty())
CanonBlockChain<Ethash>::forceGenesisExtraData(sha3(privateChain).asBytes());
if (!genesisJSON.empty())
CanonBlockChain<Ethash>::setGenesis(genesisJSON);
if (g_logVerbosity > 0) if (g_logVerbosity > 0)
{ {
cout << EthGrayBold "(++)Ethereum" EthReset << endl; cout << EthGrayBold "(++)Ethereum" EthReset << endl;
@ -1529,8 +1554,9 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
netPrefs.discovery = !disableDiscovery; netPrefs.discovery = privateChain.empty() && !disableDiscovery;
netPrefs.pin = pinning; netPrefs.pin = pinning || !privateChain.empty();
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
WebThreeDirect::composeClientVersion("++eth", clientName), WebThreeDirect::composeClientVersion("++eth", clientName),
@ -1632,7 +1658,7 @@ int main(int argc, char** argv)
cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl; cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
return 0; return 0;
} }
/*
if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing) if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing)
{ {
auto pd = contents(getDataDir() + "primes"); auto pd = contents(getDataDir() + "primes");
@ -1652,7 +1678,7 @@ int main(int argc, char** argv)
primes.insert(prime); primes.insert(prime);
writeFile(getDataDir() + "primes", rlp(primes)); writeFile(getDataDir() + "primes", rlp(primes));
} }
*/
if (keyManager.exists()) if (keyManager.exists())
{ {
if (masterPassword.empty() || !keyManager.load(masterPassword)) if (masterPassword.empty() || !keyManager.load(masterPassword))

6
ethminer/MinerAux.h

@ -398,6 +398,12 @@ private:
cdebug << genesis.boundary(); cdebug << genesis.boundary();
GenericFarm<EthashProofOfWork> f; GenericFarm<EthashProofOfWork> f;
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif
f.setSealers(sealers);
f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : "";

15
exp/main.cpp

@ -284,6 +284,21 @@ int main()
return 0; return 0;
} }
#elif 1 #elif 1
int main()
{
bytes tx = fromHex("f84c01028332dcd58004801ba024843272ee176277535489859cbd275686023fe64aabd158b6fcdf2ae6a1ab6ba02f252a5016a48e5ec8d17aefaf4324d29b9e123fa623dc5a60539b3ad3610c95");
Transaction t(tx, CheckTransaction::None);
Public p = recover(t.signature(), t.sha3(WithoutSignature));
cnote << t.signature().r;
cnote << t.signature().s;
cnote << t.signature().v;
cnote << p;
cnote << toAddress(p);
cnote << t.sender();
}
#elif 0
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
{ {
s.commitToMine(_bc); s.commitToMine(_bc);

2
libdevcore/Common.cpp

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

2
libdevcore/Exceptions.h

@ -56,7 +56,7 @@ DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(NoNetworking); DEV_SIMPLE_EXCEPTION(NoNetworking);
DEV_SIMPLE_EXCEPTION(NoUPnPDevice); DEV_SIMPLE_EXCEPTION(NoUPnPDevice);
DEV_SIMPLE_EXCEPTION(RootNotFound); DEV_SIMPLE_EXCEPTION(RootNotFound);
DEV_SIMPLE_EXCEPTION(BadRoot); struct BadRoot: virtual Exception { public: BadRoot(h256 const& _root): Exception("BadRoot " + _root.hex()), root(_root) {} h256 root; };
DEV_SIMPLE_EXCEPTION(FileError); DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(Overflow); DEV_SIMPLE_EXCEPTION(Overflow);
DEV_SIMPLE_EXCEPTION(FailedInvariant); DEV_SIMPLE_EXCEPTION(FailedInvariant);

2
libdevcore/TrieDB.h

@ -96,7 +96,7 @@ public:
/// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty).
bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); }
h256 const& root() const { if (node(m_root).empty()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. h256 const& root() const { if (node(m_root).empty()) BOOST_THROW_EXCEPTION(BadRoot(m_root)); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly.
std::string at(bytes const& _key) const { return at(&_key); } std::string at(bytes const& _key) const { return at(&_key); }
std::string at(bytesConstRef _key) const; std::string at(bytesConstRef _key) const;

10
libdevcrypto/Common.cpp

@ -193,17 +193,23 @@ bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _ci
} }
} }
static const Public c_zeroKey("3f17f1962b36e491b30a40b2405849e597ba5fb5");
Public dev::recover(Signature const& _sig, h256 const& _message) Public dev::recover(Signature const& _sig, h256 const& _message)
{ {
Public ret;
#ifdef ETH_HAVE_SECP256K1 #ifdef ETH_HAVE_SECP256K1
bytes o(65); bytes o(65);
int pubkeylen; int pubkeylen;
if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64])) if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64]))
return Public(); return Public();
return FixedHash<64>(o.data()+1, Public::ConstructFromPointer); ret = FixedHash<64>(o.data() + 1, Public::ConstructFromPointer);
#else #else
return s_secp256k1pp.recover(_sig, _message.ref()); ret = s_secp256k1pp.recover(_sig, _message.ref());
#endif #endif
if (ret == c_zeroKey)
return Public();
return ret;
} }
Signature dev::sign(Secret const& _k, h256 const& _hash) Signature dev::sign(Secret const& _k, h256 const& _hash)

2
libdevcrypto/CryptoPP.cpp

@ -287,6 +287,8 @@ Public Secp256k1PP::recover(Signature _signature, bytesConstRef _message)
{ {
// todo: make generator member // todo: make generator member
p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
if (p.identity)
return Public();
m_curve.EncodePoint(recoveredbytes, p, false); m_curve.EncodePoint(recoveredbytes, p, false);
} }
memcpy(recovered.data(), &recoveredbytes[1], 64); memcpy(recovered.data(), &recoveredbytes[1], 64);

18
libethcore/BlockInfo.cpp

@ -183,28 +183,30 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent)
{ {
m_stateRoot = _parent.stateRoot(); m_stateRoot = _parent.stateRoot();
m_number = _parent.m_number + 1; m_number = _parent.m_number + 1;
m_parentHash = _parent.m_hash;
m_gasLimit = selectGasLimit(_parent); m_gasLimit = selectGasLimit(_parent);
m_gasUsed = 0; m_gasUsed = 0;
m_difficulty = calculateDifficulty(_parent); m_difficulty = calculateDifficulty(_parent);
m_parentHash = _parent.m_hash;
} }
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
{ {
if (!m_parentHash) static const u256 c_gasFloorTarget = 3141592;
return c_genesisGasLimit;
if (!m_number)
throw GenesisBlockCannotBeCalculated();
else else
// target minimum of 3141592 // target minimum of 3141592
if (_parent.m_gasLimit < c_genesisGasLimit) if (_parent.m_gasLimit < c_gasFloorTarget)
return min<u256>(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); return min<u256>(c_gasFloorTarget, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1);
else else
return max<u256>(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); return max<u256>(c_gasFloorTarget, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
} }
u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
{ {
if (!m_parentHash) if (!m_number)
return (u256)c_genesisDifficulty; throw GenesisBlockCannotBeCalculated();
else else
return max<u256>(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); return max<u256>(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor)));
} }

1
libethcore/BlockInfo.h

@ -53,6 +53,7 @@ enum BlockDataType
}; };
DEV_SIMPLE_EXCEPTION(NoHashRecorded); DEV_SIMPLE_EXCEPTION(NoHashRecorded);
DEV_SIMPLE_EXCEPTION(GenesisBlockCannotBeCalculated);
/** @brief Encapsulation of a block header. /** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate * Class to contain all of a block header's data. It is able to parse a block header and populate

17
libethcore/Common.cpp

@ -29,6 +29,7 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "Params.h"
#include "BlockInfo.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -51,11 +52,23 @@ const unsigned c_databaseVersionModifier = 0;
#endif #endif
#if ETH_FRONTIER #if ETH_FRONTIER
Network const c_network = Network::Frontier; Network c_network = resetNetwork(Network::Frontier);
#else #else
Network const c_network = Network::Olympic; Network c_network = resetNetwork(Network::Olympic);
#endif #endif
Network resetNetwork(Network _n)
{
c_network = _n;
c_maximumExtraDataSize = c_network == Network::Olympic ? 1024 : 32;
c_minGasLimit = c_network == Network::Turbo ? 100000000 : 125000;
c_gasLimitBoundDivisor = 1024;
c_minimumDifficulty = 131072;
c_difficultyBoundDivisor = 2048;
c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12;
return _n;
}
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9);
vector<pair<u256, string>> const& units() vector<pair<u256, string>> const& units()

4
libethcore/Common.h

@ -50,7 +50,9 @@ enum class Network
Frontier = 1, Frontier = 1,
Turbo = 2 Turbo = 2
}; };
extern const Network c_network; extern Network c_network;
Network resetNetwork(Network _n);
/// User-friendly string representation of the amount _b in wei. /// User-friendly string representation of the amount _b in wei.
std::string formatBalance(bigint const& _b); std::string formatBalance(bigint const& _b);

4
libethcore/EthashSealEngine.cpp

@ -63,9 +63,11 @@ void EthashSealEngine::onSealGenerated(std::function<void(bytes const&)> const&
{ {
m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol)
{ {
cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; // cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value;
m_sealing.m_mixHash = sol.mixHash; m_sealing.m_mixHash = sol.mixHash;
m_sealing.m_nonce = sol.nonce; m_sealing.m_nonce = sol.nonce;
if (!m_sealing.preVerify())
return false;
RLPStream ret; RLPStream ret;
m_sealing.streamRLP(ret); m_sealing.streamRLP(ret);
_f(ret.out()); _f(ret.out());

2
libethcore/Miner.h

@ -58,6 +58,8 @@ public:
using Solution = typename PoW::Solution; using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>; using Miner = GenericMiner<PoW>;
virtual ~GenericFarmFace() {}
/** /**
* @brief Called from a Miner to note a WorkPackage has a solution. * @brief Called from a Miner to note a WorkPackage has a solution.
* @param _p The solution. * @param _p The solution.

14
libethcore/Params.cpp

@ -29,14 +29,12 @@ namespace eth
{ {
//--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json //--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json
u256 const c_genesisDifficulty = 131072; u256 c_maximumExtraDataSize;
u256 const c_maximumExtraDataSize = 1024; u256 c_minGasLimit;
u256 const c_genesisGasLimit = c_network == Network::Turbo ? 100000000 : 3141592; u256 c_gasLimitBoundDivisor;
u256 const c_minGasLimit = c_network == Network::Turbo ? 100000000 : 125000; u256 c_minimumDifficulty;
u256 const c_gasLimitBoundDivisor = 1024; u256 c_difficultyBoundDivisor;
u256 const c_minimumDifficulty = 131072; u256 c_durationLimit;
u256 const c_difficultyBoundDivisor = 2048;
u256 const c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12;
//--- END: AUTOGENERATED FROM /feeStructure.json //--- END: AUTOGENERATED FROM /feeStructure.json
} }

15
libethcore/Params.h

@ -29,14 +29,13 @@ namespace eth
{ {
//--- BEGIN: AUTOGENERATED FROM /feeStructure.json //--- BEGIN: AUTOGENERATED FROM /feeStructure.json
extern u256 const c_genesisGasLimit; extern u256 c_minGasLimit;
extern u256 const c_minGasLimit; extern u256 c_gasLimitBoundDivisor;
extern u256 const c_gasLimitBoundDivisor; extern u256 c_minimumDifficulty;
extern u256 const c_genesisDifficulty; extern u256 c_difficultyBoundDivisor;
extern u256 const c_minimumDifficulty; extern u256 c_durationLimit;
extern u256 const c_difficultyBoundDivisor; extern u256 c_maximumExtraDataSize;
extern u256 const c_durationLimit; //--- END: AUTOGENERATED FROM /feeStructure.json
extern u256 const c_maximumExtraDataSize;
} }
} }

2
libethcore/Sealer.h

@ -38,6 +38,8 @@ class BlockInfo;
class SealEngineFace class SealEngineFace
{ {
public: public:
virtual ~SealEngineFace() {}
virtual std::string name() const = 0; virtual std::string name() const = 0;
virtual unsigned revision() const = 0; virtual unsigned revision() const = 0;
virtual unsigned sealFields() const = 0; virtual unsigned sealFields() const = 0;

34
libethereum/BlockChain.cpp

@ -147,7 +147,12 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif #endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p):
m_genesisState(_genesisState) m_dbPath(_path)
{
open(_genesisBlock, _genesisState, _path, _we, _p);
}
void BlockChain::open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
{ {
// initialise deathrow. // initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize); m_cacheUsage.resize(c_collectionQueueSize);
@ -156,11 +161,12 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, A
// Initialise with the genesis as the last block on the longest chain. // Initialise with the genesis as the last block on the longest chain.
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
m_genesisState = _genesisState;
// remove the next line real soon. we don't need to be supporting this forever. // remove the next line real soon. we don't need to be supporting this forever.
upgradeDatabase(_path, genesisHash()); upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion) if (openDatabase(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p); rebuild(_path, _p);
} }
@ -169,7 +175,7 @@ BlockChain::~BlockChain()
close(); close();
} }
unsigned BlockChain::open(std::string const& _path, WithExisting _we) unsigned BlockChain::openDatabase(std::string const& _path, WithExisting _we)
{ {
string path = _path.empty() ? Defaults::get()->m_dbPath : _path; string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4)); string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4));
@ -220,8 +226,9 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we)
if (_we != WithExisting::Verify && !details(m_genesisHash)) if (_we != WithExisting::Verify && !details(m_genesisHash))
{ {
BlockInfo gb(m_genesisBlock);
// Insert details of genesis block. // Insert details of genesis block.
m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}); m_details[m_genesisHash] = BlockDetails(0, gb.difficulty(), h256(), {});
auto r = m_details[m_genesisHash].rlp(); auto r = m_details[m_genesisHash].rlp();
m_extrasDB->Put(m_writeOptions, toSlice(m_genesisHash, ExtraDetails), (ldb::Slice)dev::ref(r)); m_extrasDB->Put(m_writeOptions, toSlice(m_genesisHash, ExtraDetails), (ldb::Slice)dev::ref(r));
} }
@ -243,12 +250,22 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we)
void BlockChain::close() void BlockChain::close()
{ {
cnote << "Closing blockchain DB"; cnote << "Closing blockchain DB";
// Not thread safe...
delete m_extrasDB; delete m_extrasDB;
delete m_blocksDB; delete m_blocksDB;
m_lastBlockHash = m_genesisHash; m_lastBlockHash = m_genesisHash;
m_lastBlockNumber = 0; m_lastBlockNumber = 0;
m_details.clear(); m_details.clear();
m_blocks.clear(); m_blocks.clear();
m_logBlooms.clear();
m_receipts.clear();
m_transactionAddresses.clear();
m_blockHashes.clear();
m_blocksBlooms.clear();
m_cacheUsage.clear();
m_inUse.clear();
m_lastLastHashes.clear();
m_lastLastHashesNumber = (unsigned)-1;
} }
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW) void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW)
@ -293,7 +310,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
m_lastBlockHash = genesisHash(); m_lastBlockHash = genesisHash();
m_lastBlockNumber = 0; m_lastBlockNumber = 0;
m_details[m_lastBlockHash].totalDifficulty = c_genesisDifficulty; m_details[m_lastBlockHash].totalDifficulty = BlockInfo(m_genesisBlock).difficulty();
m_extrasDB->Put(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp()));
@ -586,9 +603,11 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
#endif #endif
} }
#if ETH_CATCH #if ETH_CATCH
catch (BadRoot&) catch (BadRoot& ex)
{ {
cwarn << "BadRoot error. Retrying import later."; cwarn << "*** BadRoot error! Trying to import" << _block.info.hash() << "needed root" << ex.root;
cwarn << _block.info;
// Attempt in import later.
BOOST_THROW_EXCEPTION(FutureTime()); BOOST_THROW_EXCEPTION(FutureTime());
} }
catch (Exception& ex) catch (Exception& ex)
@ -1245,6 +1264,7 @@ State BlockChain::genesisState(OverlayDB const& _db)
dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it?
ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(&m_genesisBlock); ret.m_previousBlock = BlockInfo(&m_genesisBlock);
ret.resetCurrent();
return ret; return ret;
} }

21
libethereum/BlockChain.h

@ -106,8 +106,8 @@ public:
BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
~BlockChain(); ~BlockChain();
/// Attempt a database re-open. /// Reopen everything.
void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust) { close(); open(_path, _we); } virtual void reopen(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()) { close(); open(m_genesisBlock, m_genesisState, m_dbPath, _we, _pc); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so. /// To be called from main loop every 100ms or so.
@ -291,7 +291,11 @@ public:
protected: protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); /// Initialise everything and open the database.
void open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p);
/// Open the database.
unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust);
/// Finalise everything and close the database.
void close(); void close();
template<class T, class K, unsigned N> T queryExtras(K const& _h, std::unordered_map<K, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const template<class T, class K, unsigned N> T queryExtras(K const& _h, std::unordered_map<K, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const
@ -373,6 +377,8 @@ protected:
std::function<void(Exception&)> m_onBad; ///< Called if we have a block that doesn't verify. std::function<void(Exception&)> m_onBad; ///< Called if we have a block that doesn't verify.
std::string m_dbPath;
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
}; };
@ -393,10 +399,10 @@ public:
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const override virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const override
{ {
VerifiedBlockRef res; VerifiedBlockRef res;
BlockHeader h;
try try
{ {
BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h = BlockHeader(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h.verifyInternals(_block); h.verifyInternals(_block);
if ((_ir & ImportRequirements::Parent) != 0) if ((_ir & ImportRequirements::Parent) != 0)
{ {
@ -412,6 +418,7 @@ public:
ex << errinfo_phase(1); ex << errinfo_phase(1);
ex << errinfo_now(time(0)); ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes()); ex << errinfo_block(_block.toBytes());
ex << errinfo_extraData(h.extraData());
if (_onBad) if (_onBad)
_onBad(ex); _onBad(ex);
throw; throw;
@ -422,9 +429,10 @@ public:
if (_ir && ImportRequirements::UncleBasic) if (_ir && ImportRequirements::UncleBasic)
for (auto const& uncle: r[2]) for (auto const& uncle: r[2])
{ {
BlockHeader h;
try try
{ {
BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); h.populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal);
} }
catch (Exception& ex) catch (Exception& ex)
{ {
@ -432,6 +440,7 @@ public:
ex << errinfo_uncleIndex(i); ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0)); ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes()); ex << errinfo_block(_block.toBytes());
ex << errinfo_extraData(h.extraData());
if (_onBad) if (_onBad)
_onBad(ex); _onBad(ex);
throw; throw;

54
libethereum/CanonBlockChain.cpp

@ -38,18 +38,23 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
#define ETH_CATCH 1 unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
std::unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis; boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
Nonce CanonBlockChain<Ethash>::s_nonce(u64(42)); Nonce CanonBlockChain<Ethash>::s_nonce(u64(42));
std::string CanonBlockChain<Ethash>::s_genesisStateJSON; string CanonBlockChain<Ethash>::s_genesisStateJSON;
bytes CanonBlockChain<Ethash>::s_genesisExtraData;
CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc) FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc)
{ {
} }
void CanonBlockChain<Ethash>::reopen(WithExisting _we, ProgressCallback const& _pc)
{
close();
open(createGenesisBlock(), createGenesisState(), m_dbPath, _we, _pc);
}
bytes CanonBlockChain<Ethash>::createGenesisBlock() bytes CanonBlockChain<Ethash>::createGenesisBlock()
{ {
RLPStream block(3); RLPStream block(3);
@ -63,8 +68,35 @@ bytes CanonBlockChain<Ethash>::createGenesisBlock()
stateRoot = state.root(); stateRoot = state.root();
} }
js::mValue val;
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
js::mObject genesis = val.get_obj();
h256 mixHash(genesis["mixhash"].get_str());
h256 parentHash(genesis["parentHash"].get_str());
h160 beneficiary(genesis["coinbase"].get_str());
u256 difficulty = fromBigEndian<u256>(fromHex(genesis["difficulty"].get_str()));
u256 gasLimit = fromBigEndian<u256>(fromHex(genesis["gasLimit"].get_str()));
u256 timestamp = fromBigEndian<u256>(fromHex(genesis["timestamp"].get_str()));
bytes extraData = fromHex(genesis["extraData"].get_str());
h64 nonce(genesis["nonce"].get_str());
block.appendList(15) block.appendList(15)
<< h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; << parentHash
<< EmptyListSHA3 // sha3(uncles)
<< beneficiary
<< stateRoot
<< EmptyTrie // transactions
<< EmptyTrie // receipts
<< LogBloom()
<< difficulty
<< 0 // number
<< gasLimit
<< 0 // gasUsed
<< timestamp
<< (s_genesisExtraData.empty() ? extraData : s_genesisExtraData)
<< mixHash
<< nonce;
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
return block.out(); return block.out();
@ -78,12 +110,14 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
{ {
js::mValue val; js::mValue val;
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
for (auto account: val.get_obj()) for (auto account: val.get_obj()["alloc"].get_obj())
{ {
u256 balance; u256 balance;
if (account.second.get_obj().count("wei")) if (account.second.get_obj().count("wei"))
balance = u256(account.second.get_obj()["wei"].get_str()); balance = u256(account.second.get_obj()["wei"].get_str());
else else if (account.second.get_obj().count("balance"))
balance = u256(account.second.get_obj()["balance"].get_str());
else if (account.second.get_obj().count("finney"))
balance = u256(account.second.get_obj()["finney"].get_str()) * finney; balance = u256(account.second.get_obj()["finney"].get_str()) * finney;
if (account.second.get_obj().count("code")) if (account.second.get_obj().count("code"))
{ {
@ -97,17 +131,17 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
return s_ret; return s_ret;
} }
void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json) void CanonBlockChain<Ethash>::setGenesis(std::string const& _json)
{ {
WriteGuard l(x_genesis); WriteGuard l(x_genesis);
s_genesisStateJSON = _json; s_genesisStateJSON = _json;
s_genesis.reset(); s_genesis.reset();
} }
void CanonBlockChain<Ethash>::setGenesisNonce(Nonce const& _n) void CanonBlockChain<Ethash>::forceGenesisExtraData(bytes const& _genesisExtraData)
{ {
WriteGuard l(x_genesis); WriteGuard l(x_genesis);
s_nonce = _n; s_genesisExtraData = _genesisExtraData;
s_genesis.reset(); s_genesis.reset();
} }

15
libethereum/CanonBlockChain.h

@ -78,6 +78,9 @@ public:
CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()); CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
~CanonBlockChain() {} ~CanonBlockChain() {}
/// Reopen everything.
virtual void reopen(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
/// @returns the genesis block header. /// @returns the genesis block header.
static Ethash::BlockHeader const& genesis(); static Ethash::BlockHeader const& genesis();
@ -89,18 +92,13 @@ public:
/// @note This is slow as it's constructed anew each call. Consider genesis() instead. /// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static std::unordered_map<Address, Account> createGenesisState(); static std::unordered_map<Address, Account> createGenesisState();
/// Alter the value of the genesis block's nonce.
/// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all.
static void setGenesisNonce(Nonce const& _n);
/// Alter all the genesis block's state by giving a JSON string with account details. /// Alter all the genesis block's state by giving a JSON string with account details.
/// @TODO implement.
/// @warning Unless you're very careful, make sure you call this right at the start of the /// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all. /// program, before anything has had the chance to use this class at all.
static void setGenesisState(std::string const&); static void setGenesis(std::string const& _genesisInfoJSON);
// TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, /// Override the genesis block's extraData field.
static void forceGenesisExtraData(bytes const& _genesisExtraData);
private: private:
/// Static genesis info and its lock. /// Static genesis info and its lock.
@ -108,6 +106,7 @@ private:
static std::unique_ptr<Ethash::BlockHeader> s_genesis; static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce; static Nonce s_nonce;
static std::string s_genesisStateJSON; static std::string s_genesisStateJSON;
static bytes s_genesisExtraData;
}; };
} }

31
libethereum/Client.cpp

@ -217,6 +217,17 @@ void Client::onBadBlock(Exception& _ex) const
report["hints"]["ethashResult"]["value"] = get<0>(*r).hex(); report["hints"]["ethashResult"]["value"] = get<0>(*r).hex();
report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex(); report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex();
} }
if (bytes const* ed = boost::get_error_info<errinfo_extraData>(_ex))
{
RLP r(*ed);
report["hints"]["extraData"] = toHex(*ed);
try
{
if (r[0].toInt<int>() == 0)
report["hints"]["minerVersion"] = r[1].toString();
}
catch (...) {}
}
DEV_HINT_ERRINFO(required); DEV_HINT_ERRINFO(required);
DEV_HINT_ERRINFO(got); DEV_HINT_ERRINFO(got);
DEV_HINT_ERRINFO_HASH(required_LogBloom); DEV_HINT_ERRINFO_HASH(required_LogBloom);
@ -316,7 +327,7 @@ void Client::doneWorking()
} }
} }
void Client::killChain() void Client::reopenChain(WithExisting _we)
{ {
bool wasMining = isMining(); bool wasMining = isMining();
if (wasMining) if (wasMining)
@ -337,11 +348,11 @@ void Client::killChain()
m_working = State(); m_working = State();
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); bc().reopen(_we);
bc().reopen(Defaults::dbPath(), WithExisting::Kill); m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), _we);
m_preMine = bc().genesisState(m_stateDB); m_preMine = bc().genesisState(m_stateDB);
m_postMine = State(m_stateDB); m_postMine = m_preMine;
} }
if (auto h = m_host.lock()) if (auto h = m_host.lock())
@ -450,6 +461,14 @@ void Client::setShouldPrecomputeDAG(bool _precompute)
sealEngine()->setOption("precomputeDAG", _precompute ? trueBytes: falseBytes); sealEngine()->setOption("precomputeDAG", _precompute ? trueBytes: falseBytes);
} }
void Client::setTurboMining(bool _enable)
{
m_turboMining = _enable;
sealEngine()->setSealer("opencl");
if (isMining())
startMining();
}
bool Client::isMining() const bool Client::isMining() const
{ {
return Ethash::isWorking(m_sealEngine.get()); return Ethash::isWorking(m_sealEngine.get());
@ -586,7 +605,7 @@ void Client::onNewBlocks(h256s const& _blocks, h256Hash& io_changed)
appendFromBlock(h, BlockPolarity::Live, io_changed); appendFromBlock(h, BlockPolarity::Live, io_changed);
} }
void Client::restartMining() void Client::resyncStateFromChain()
{ {
// RESTART MINING // RESTART MINING
@ -639,7 +658,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
m_tq.dropGood(t); m_tq.dropGood(t);
} }
onNewBlocks(_ir.liveBlocks, changeds); onNewBlocks(_ir.liveBlocks, changeds);
restartMining(); resyncStateFromChain();
noteChanged(changeds); noteChanged(changeds);
} }

51
libethereum/Client.h

@ -79,10 +79,6 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r);
class Client: public ClientBase, protected Worker class Client: public ClientBase, protected Worker
{ {
public: public:
/// New-style Constructor.
/// Any final derived class's constructor should make sure they call init().
explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
/// Destructor. /// Destructor.
virtual ~Client(); virtual ~Client();
@ -139,7 +135,7 @@ public:
/// Are we allowed to GPU mine? /// Are we allowed to GPU mine?
bool turboMining() const { return m_turboMining; } bool turboMining() const { return m_turboMining; }
/// Enable/disable GPU mining. /// Enable/disable GPU mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); } void setTurboMining(bool _enable = true);
/// Enable/disable precomputing of the DAG for next epoch /// Enable/disable precomputing of the DAG for next epoch
void setShouldPrecomputeDAG(bool _precompute); void setShouldPrecomputeDAG(bool _precompute);
@ -180,7 +176,9 @@ public:
/// Clears pending transactions. Just for debug use. /// Clears pending transactions. Just for debug use.
void clearPending(); void clearPending();
/// Kills the blockchain. Just for debug use. /// Kills the blockchain. Just for debug use.
void killChain(); void killChain() { reopenChain(WithExisting::Kill); }
/// Reloads the blockchain. Just for debug use.
void reopenChain(WithExisting _we = WithExisting::Trust);
/// Retries all blocks with unknown parents. /// Retries all blocks with unknown parents.
void retryUnknown() { m_bq.retryAllUnknown(); } void retryUnknown() { m_bq.retryAllUnknown(); }
/// Get a report of activity. /// Get a report of activity.
@ -199,6 +197,10 @@ public:
SealEngineFace* sealEngine() const { return m_sealEngine.get(); } SealEngineFace* sealEngine() const { return m_sealEngine.get(); }
protected: protected:
/// New-style Constructor.
/// Any final derived class's constructor should make sure they call init().
explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
/// Perform critical setup functions. /// Perform critical setup functions.
/// Must be called in the constructor of the finally derived class. /// Must be called in the constructor of the finally derived class.
void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId);
@ -250,7 +252,7 @@ protected:
void onNewBlocks(h256s const& _blocks, h256Hash& io_changed); void onNewBlocks(h256s const& _blocks, h256Hash& io_changed);
/// Called after processing blocks by onChainChanged(_ir) /// Called after processing blocks by onChainChanged(_ir)
void restartMining(); void resyncStateFromChain();
/// Magically called when the chain has changed. An import route is provided. /// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue(). /// Called by either submitWork() or in our main thread through syncBlockQueue().
@ -342,13 +344,8 @@ public:
WithExisting _forceAction = WithExisting::Trust, WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0 u256 _networkId = 0
): ):
Client(_gpForAdoption), SpecialisedClient(_gpForAdoption, _dbPath, _forceAction)
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; })
{ {
m_sealEngine = std::shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSealGenerated([=](bytes const& header){
this->submitSealed(header);
});
init(_host, _dbPath, _forceAction, _networkId); init(_host, _dbPath, _forceAction, _networkId);
} }
@ -358,10 +355,24 @@ public:
CanonBlockChain<Sealer> const& blockChain() const { return m_bc; } CanonBlockChain<Sealer> const& blockChain() const { return m_bc; }
protected: protected:
explicit SpecialisedClient(
std::shared_ptr<GasPricer> _gpForAdoption,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust
):
Client(_gpForAdoption),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; })
{
m_sealEngine = std::shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSealGenerated([=](bytes const& header){
this->submitSealed(header);
});
}
virtual BlockChain& bc() override { return m_bc; } virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; } virtual BlockChain const& bc() const override { return m_bc; }
protected: private:
CanonBlockChain<Sealer> m_bc; ///< Maintains block database. CanonBlockChain<Sealer> m_bc; ///< Maintains block database.
}; };
@ -375,9 +386,11 @@ public:
std::string const& _dbPath = std::string(), std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust, WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0 u256 _networkId = 0
): SpecialisedClient<Ethash>(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} ):
SpecialisedClient<Ethash>(_gpForAdoption, _dbPath, _forceAction)
virtual ~EthashClient() { stopWorking(); } {
init(_host, _dbPath, _forceAction, _networkId);
}
/// Update to the latest transactions and get hash of the current block to be mined minus the /// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met. /// nonce (the 'work hash') and the difficulty to be met.
@ -389,10 +402,6 @@ public:
* @return true if the solution was indeed valid and accepted. * @return true if the solution was indeed valid and accepted.
*/ */
virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override;
protected:
virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; }
}; };
} }

34
libethereum/GenesisInfo.cpp

@ -24,17 +24,27 @@
std::string const dev::eth::c_genesisInfo = std::string const dev::eth::c_genesisInfo =
R"ETHEREUM( R"ETHEREUM(
{ {
"0000000000000000000000000000000000000001": { "wei": "1" }, "nonce": "0x000000000000002a",
"0000000000000000000000000000000000000002": { "wei": "1" }, "difficulty": "0x20000",
"0000000000000000000000000000000000000003": { "wei": "1" }, "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0000000000000000000000000000000000000004": { "wei": "1" }, "coinbase": "0x0000000000000000000000000000000000000000",
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "timestamp": "0x00",
"e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "extraData": "0x",
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "gasLimit": "0x2FEFD8",
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "alloc": {
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "0000000000000000000000000000000000000001": { "wei": "1" },
"6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "0000000000000000000000000000000000000002": { "wei": "1" },
"e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "0000000000000000000000000000000000000003": { "wei": "1" },
"0000000000000000000000000000000000000004": { "wei": "1" },
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }
}
} }
)ETHEREUM"; )ETHEREUM";

1
libethereum/State.h

@ -52,6 +52,7 @@ using errinfo_uncleNumber = boost::error_info<struct tag_uncleNumber, u256>;
using errinfo_unclesExcluded = boost::error_info<struct tag_unclesExcluded, h256Hash>; using errinfo_unclesExcluded = boost::error_info<struct tag_unclesExcluded, h256Hash>;
using errinfo_block = boost::error_info<struct tag_block, bytes>; using errinfo_block = boost::error_info<struct tag_block, bytes>;
using errinfo_now = boost::error_info<struct tag_now, unsigned>; using errinfo_now = boost::error_info<struct tag_now, unsigned>;
using errinfo_extraData = boost::error_info<struct tag_extraData, bytes>;
using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex, unsigned>; using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex, unsigned>;

2
libwebthree/WebThree.cpp

@ -53,7 +53,7 @@ WebThreeDirect::WebThreeDirect(
if (_interfaces.count("eth")) if (_interfaces.count("eth"))
{ {
m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr<GasPricer>(), _dbPath, _we, 0)); m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr<GasPricer>(), _dbPath, _we, 0));
m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); m_ethereum->setExtraData(rlpList(0, _clientVersion));
} }
if (_interfaces.count("shh")) if (_interfaces.count("shh"))

2
mix/QBigInt.h

@ -82,6 +82,8 @@ public:
BigIntVariant internalValue() const { return m_internalValue; } BigIntVariant internalValue() const { return m_internalValue; }
/// @returns a string representation of the big integer used. Invokable from QML. /// @returns a string representation of the big integer used. Invokable from QML.
Q_INVOKABLE QString value() const; Q_INVOKABLE QString value() const;
/// hex value.
Q_INVOKABLE QString hexValue() const { return QString::fromStdString(dev::toHex(dev::u256(value().toStdString()))); }
/// Set the value of the BigInteger used. Will use u256 type. Invokable from QML. /// Set the value of the BigInteger used. Will use u256 type. Invokable from QML.
Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); } Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); }
Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); } Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); }

2
mix/QFunctionDefinition.h

@ -55,6 +55,8 @@ public:
FixedHash<4> hash() const { return m_hash; } FixedHash<4> hash() const { return m_hash; }
/// Get the full hash of this function declaration on the contract ABI. /// Get the full hash of this function declaration on the contract ABI.
FixedHash<32> fullHash() const { return m_fullHash; } FixedHash<32> fullHash() const { return m_fullHash; }
/// Get the hash of this function declaration on the contract ABI. returns QString
Q_INVOKABLE QString qhash() const { return QString::fromStdString(m_hash.hex()); }
private: private:
int m_index; int m_index;

1
mix/qml/Block.qml

@ -105,6 +105,7 @@ ColumnLayout
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 14 anchors.rightMargin: 14
visible: false
MouseArea MouseArea
{ {
anchors.fill: parent anchors.fill: parent

54
mix/qml/BlockChain.qml

@ -117,47 +117,7 @@ ColumnLayout {
RowLayout RowLayout
{ {
id: header Layout.preferredHeight: 10
spacing: 0
Layout.preferredHeight: 24
Rectangle
{
Layout.preferredWidth: statusWidth
Layout.preferredHeight: parent.height
color: "transparent"
Image {
id: debugImage
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
source: "qrc:/qml/img/recycleicon@2x.png"
width: statusWidth + 10
fillMode: Image.PreserveAspectFit
}
}
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: fromWidth
Label
{
anchors.verticalCenter: parent.verticalCenter
text: "From"
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
}
}
Label
{
text: "To"
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: toWidth + cellSpacing
}
Label
{
text: ""
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: debugActionWidth
}
} }
Rectangle Rectangle
@ -178,18 +138,6 @@ ColumnLayout {
width: parent.width width: parent.width
spacing: 20 spacing: 20
Block
{
scenario: blockChainPanel.model
Layout.preferredWidth: blockChainScrollView.width
Layout.preferredHeight: 60
blockIndex: -1
transactions: []
status: ""
number: -2
trHeight: 60
}
Repeater // List of blocks Repeater // List of blocks
{ {
id: blockChainRepeater id: blockChainRepeater

198
mix/qml/DeployContractStep.qml

@ -12,12 +12,15 @@ Rectangle {
property variant paramsModel: [] property variant paramsModel: []
property variant worker property variant worker
property variant gas: [] property variant gas: []
property alias gasPrice: gasPriceInput
color: "#E3E3E3E3" color: "#E3E3E3E3"
signal deployed
anchors.fill: parent anchors.fill: parent
id: root id: root
property int labelWidth: 150 property int labelWidth: 150
function show() function show()
{ {
visible = true visible = true
@ -25,12 +28,13 @@ Rectangle {
contractList.change() contractList.change()
accountsModel.clear() accountsModel.clear()
for (var k in worker.accounts) for (var k in worker.accounts)
{
accountsModel.append(worker.accounts[k]) accountsModel.append(worker.accounts[k])
}
if (worker.accounts.length > 0) if (worker.currentAccount === "" && worker.accounts.length > 0)
{
worker.currentAccount = worker.accounts[0].id worker.currentAccount = worker.accounts[0].id
accountsList.currentIndex = 0
}
if (projectModel.deployBlockNumber !== -1) if (projectModel.deployBlockNumber !== -1)
{ {
@ -45,13 +49,28 @@ Rectangle {
function updateVerification(blockNumber, trLost) function updateVerification(blockNumber, trLost)
{ {
verificationLabel.text = blockNumber - projectModel.deployBlockNumber var nb = parseInt(blockNumber - projectModel.deployBlockNumber)
if (trLost.length > 0) verificationTextArea.visible = false
verificationLabel.visible = true
if (nb >= 10)
{ {
verificationLabel.text += "\n" + qsTr("Transactions lost") + "\n" verificationLabel.text = qsTr("contracts deployment verified")
for (var k in trLost) verificationLabel.color = "green"
}
else
{
verificationLabel.text = nb
if (trLost.length > 0)
{ {
verificationLabel.text += trLost[k] + "\n" verificationTextArea.visible = true
verificationLabel.visible = false
deploymentStepChanged("following transactions are invalidated:")
verificationTextArea.text += "\n" + qsTr("Transactions lost") + "\n"
for (var k in trLost)
{
deploymentStepChanged(trLost[k])
verificationTextArea.text += trLost[k] + "\n"
}
} }
} }
} }
@ -250,7 +269,6 @@ Rectangle {
{ {
worker.currentAccount = currentText worker.currentAccount = currentText
accountBalance.text = worker.balance(currentText).format() accountBalance.text = worker.balance(currentText).format()
console.log(worker.balance(currentText).format())
} }
} }
@ -280,6 +298,11 @@ Rectangle {
displayUnitSelection: true displayUnitSelection: true
displayFormattedValue: true displayFormattedValue: true
edit: true edit: true
function toHexWei()
{
return "0x" + gasPriceInput.value.toWei().hexValue()
}
} }
Connections Connections
@ -329,9 +352,7 @@ Rectangle {
root.gas = gas root.gas = gas
cost = 0 cost = 0
for (var k in gas) for (var k in gas)
{
cost += gas[k] cost += gas[k]
}
setCost() setCost()
} }
}); });
@ -349,7 +370,7 @@ Rectangle {
width: labelWidth width: labelWidth
Label Label
{ {
text: qsTr("Cost Estimate") text: qsTr("Deployment Cost")
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -365,92 +386,87 @@ Rectangle {
} }
} }
RowLayout Rectangle
{ {
id: deployedRow border.color: "#cccccc"
border.width: 2
Layout.fillWidth: true Layout.fillWidth: true
Rectangle Layout.preferredHeight: parent.height + 25
color: "transparent"
id: rectDeploymentVariable
ScrollView
{ {
width: labelWidth anchors.fill: parent
Label anchors.topMargin: 4
anchors.bottomMargin: 4
ColumnLayout
{ {
id: labelAddresses RowLayout
text: qsTr("Deployed Contracts")
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
ColumnLayout
{
anchors.top: parent.top
anchors.topMargin: 1
ListModel
{
id: deployedAddrModel
}
Repeater
{
id: deployedAddresses
model: deployedAddrModel
function refresh()
{ {
deployedAddrModel.clear() id: deployedRow
deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0 Layout.fillWidth: true
for (var k in projectModel.deploymentAddresses) Rectangle
{ {
if (k.indexOf("-") !== -1) // this is an contract instance. ctr without - are the last deployed (to support old project) width: labelWidth
deployedAddrModel.append({ id: k, value: projectModel.deploymentAddresses[k]}) Label
{
id: labelAddresses
text: qsTr("Deployed Contracts")
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
ColumnLayout
{
anchors.top: parent.top
anchors.topMargin: 1
width: parent.width
id: deployedAddresses
function refresh()
{
textAddresses.text = ""
deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0
textAddresses.text = JSON.stringify(projectModel.deploymentAddresses, null, ' ')
}
TextArea
{
anchors.fill: parent
id: textAddresses
}
} }
} }
Rectangle RowLayout
{ {
Layout.preferredHeight: 20 id: verificationRow
Layout.preferredWidth: 235 Layout.fillWidth: true
color: "transparent" visible: Object.keys(projectModel.deploymentAddresses).length > 0
Label Rectangle
{ {
id: labelContract width: labelWidth
width: 112 Label
elide: Text.ElideRight {
text: index > -1 ? deployedAddrModel.get(index).id : "" text: qsTr("Verifications")
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
} }
TextField TextArea
{ {
width: 123 id: verificationTextArea
anchors.verticalCenter: parent.verticalCenter visible: false
anchors.left: labelContract.right
text: index > - 1 ? deployedAddrModel.get(index).value : ""
} }
}
}
}
}
RowLayout Label
{ {
id: verificationRow id: verificationLabel
Layout.fillWidth: true visible: true
visible: Object.keys(projectModel.deploymentAddresses).length > 0 }
Rectangle }
{
width: labelWidth
Label
{
text: qsTr("Verifications")
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
} }
} }
Label
{
id: verificationLabel
maximumLineCount: 20
}
} }
} }
@ -460,12 +476,31 @@ Rectangle {
Layout.alignment: Qt.BottomEdge Layout.alignment: Qt.BottomEdge
Button Button
{ {
Layout.preferredHeight: 22
anchors.right: deployBtn.left
text: qsTr("Reset")
action: clearDeployAction
}
Action {
id: clearDeployAction
onTriggered: {
worker.forceStopPooling()
fileIo.deleteDir(projectModel.deploymentDir)
projectModel.cleanDeploymentStatus()
deploymentDialog.steps.reset()
}
}
Button
{
id: deployBtn
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Deploy Contracts") text: qsTr("Deploy Contracts")
onClicked: onClicked:
{ {
projectModel.deployedScenarioIndex = contractList.currentIndex projectModel.deployedScenarioIndex = contractList.currentIndex
NetworkDeploymentCode.deployContracts(root.gas, function(addresses, trHashes) NetworkDeploymentCode.deployContracts(root.gas, gasPriceInput.toHexWei(), function(addresses, trHashes)
{ {
projectModel.deploymentTrHashes = trHashes projectModel.deploymentTrHashes = trHashes
worker.verifyHashes(trHashes, function (nb, trLost) worker.verifyHashes(trHashes, function (nb, trLost)
@ -473,6 +508,7 @@ Rectangle {
projectModel.deployBlockNumber = nb projectModel.deployBlockNumber = nb
projectModel.saveProject() projectModel.saveProject()
root.updateVerification(nb, trLost) root.updateVerification(nb, trLost)
root.deployed()
}) })
projectModel.deploymentAddresses = addresses projectModel.deploymentAddresses = addresses
projectModel.saveProject() projectModel.saveProject()

21
mix/qml/DeploymentDialog.qml

@ -22,6 +22,7 @@ Dialog {
property alias packageStep: packageStep property alias packageStep: packageStep
property alias registerStep: registerStep property alias registerStep: registerStep
property alias worker: worker property alias worker: worker
property alias steps: steps
function close() function close()
{ {
@ -52,15 +53,31 @@ Dialog {
anchors.fill: parent anchors.fill: parent
anchors.margins: 10 anchors.margins: 10
RowLayout Rectangle
{ {
id: explanation id: explanation
Layout.preferredWidth: parent.width - 50 Layout.preferredWidth: parent.width - 50
Layout.preferredHeight: 50 Layout.preferredHeight: 50
color: "transparent"
Label Label
{ {
id: info
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("Putting your dapp live is a multi step process. You can read more about it on the 'guide to uploading'.") text: qsTr("Putting your dapp live is a multi step process. You can read more about it on the")
}
Text {
anchors.left: info.right
anchors.leftMargin: 7
id: linkText
text: '<html><style type="text/css"></style><a href="https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE#deployment-to-network">guide to uploading</a></html>'
onLinkActivated: Qt.openUrlExternally("https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE#deployment-to-network")
anchors.verticalCenter: parent.verticalCenter
MouseArea
{
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
} }
} }

170
mix/qml/DeploymentDialogSteps.qml

@ -26,13 +26,55 @@ Rectangle {
selected(step) selected(step)
} }
function reset()
{
for (var k in deployLogs.logs)
{
deployLogs.logs[k] = ""
}
deployLogs.switchLogs()
refreshCurrent()
}
border.color: "#cccccc" border.color: "#cccccc"
border.width: 1 border.width: 1
Connections
{
id: deployStatus
target: deploymentDialog.deployStep
onDeployed:
{
console.log("deployed")
}
}
Connections
{
id: packagedStatus
target: deploymentDialog.packageStep
onPackaged:
{
console.log("packaged")
}
}
Connections
{
id: registerStatus
target: deploymentDialog.registerStep
onRegistered:
{
console.log("registered")
}
}
ColumnLayout ColumnLayout
{ {
anchors.fill: parent anchors.fill: parent
anchors.margins: 1 anchors.margins: 1
spacing: 0
Repeater Repeater
{ {
id: menu id: menu
@ -45,7 +87,7 @@ Rectangle {
{ {
step: 2, step: 2,
type:"package", type:"package",
label: qsTr("Package files") label: qsTr("Package Dapp")
}, },
{ {
step: 3, step: 3,
@ -70,6 +112,7 @@ Rectangle {
labelContainer.state = "selected" labelContainer.state = "selected"
sel = index sel = index
itemClicked(menu.model[index].type) itemClicked(menu.model[index].type)
deployLogs.switchLogs()
} }
function unselect() function unselect()
@ -136,62 +179,60 @@ Rectangle {
} }
Connections { Connections {
target: projectModel property var logs: ({})
onDeploymentStarted: log.text = log.text + qsTr("Running deployment...") + "\n" id: deployLogs
onDeploymentError: log.text = log.text + error + "\n"
onDeploymentComplete: log.text = log.text + qsTr("Deployment complete") + "\n"
onDeploymentStepChanged: log.text = log.text + message + "\n"
}
Rectangle function switchLogs()
{ {
Layout.fillWidth: true if (root.sel)
Layout.preferredHeight: 1 {
color: "#cccccc" if (!logs[root.sel])
} logs[root.sel] = ""
log.text = logs[root.sel]
}
}
RowLayout target: projectModel
{ onDeploymentStarted:
anchors.horizontalCenter: parent.horizontalCenter
Layout.preferredHeight: 20
anchors.left: parent.left
anchors.leftMargin: 2
Button
{ {
Layout.preferredHeight: 22 if (!logs[root.sel])
Layout.preferredWidth: 22 logs[root.sel] = ""
action: clearAction logs[root.sel] = logs[root.sel] + qsTr("Running deployment...") + "\n"
iconSource: "qrc:/qml/img/cleariconactive.png" log.text = logs[root.sel]
} }
Action { onDeploymentError:
id: clearAction {
enabled: log.text !== "" if (!logs[root.sel])
tooltip: qsTr("Clear") logs[root.sel] = ""
onTriggered: { logs[root.sel] = logs[root.sel] + error + "\n"
log.text = "" log.text = logs[root.sel]
}
} }
Button onDeploymentComplete:
{ {
Layout.preferredHeight: 22 if (!logs[root.sel])
text: qsTr("Clear Deployment") logs[root.sel] = ""
action: clearDeployAction logs[root.sel] = logs[root.sel] + qsTr("Deployment complete") + "\n"
log.text = logs[root.sel]
} }
Action { onDeploymentStepChanged:
id: clearDeployAction {
onTriggered: { if (!logs[root.sel])
worker.forceStopPooling() logs[root.sel] = ""
fileIo.deleteDir(projectModel.deploymentDir) logs[root.sel] = logs[root.sel] + message + "\n"
projectModel.cleanDeploymentStatus() log.text = logs[root.sel]
root.refreshCurrent()
log.text = ""
}
} }
} }
Rectangle
{
Layout.fillWidth: true
Layout.preferredHeight: 2
color: "#cccccc"
}
ScrollView ScrollView
{ {
Layout.fillHeight: true Layout.fillHeight: true
@ -205,6 +246,47 @@ Rectangle {
id: log id: log
} }
} }
Rectangle
{
Layout.preferredHeight: 20
Layout.fillWidth: true
color: "#cccccc"
LogsPaneStyle
{
id: style
}
Label
{
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Logs")
font.italic: true
font.pointSize: style.absoluteSize(-1)
}
Button
{
height: 20
width: 20
anchors.right: parent.right
action: clearAction
iconSource: "qrc:/qml/img/cleariconactive.png"
tooltip: qsTr("Clear Messages")
}
Action {
id: clearAction
enabled: log.text !== ""
tooltip: qsTr("Clear")
onTriggered: {
deployLogs.logs[root.sel] = ""
log.text = deployLogs.logs[root.sel]
}
}
}
} }
} }

6
mix/qml/DeploymentWorker.qml

@ -38,6 +38,7 @@ Item
var ids = JSON.parse(arg2)[0].result; var ids = JSON.parse(arg2)[0].result;
requests = []; requests = [];
accounts = []
for (var k in ids) for (var k in ids)
{ {
requests.push({ requests.push({
@ -52,6 +53,7 @@ Item
TransactionHelper.rpcCall(requests, function (request, response){ TransactionHelper.rpcCall(requests, function (request, response){
var balanceRet = JSON.parse(response); var balanceRet = JSON.parse(response);
balances = {}
for (var k in balanceRet) for (var k in balanceRet)
{ {
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
@ -206,7 +208,7 @@ Item
property var callBack property var callBack
property int elapsed property int elapsed
property string hash property string hash
interval: 500 interval: 2000
running: false running: false
repeat: true repeat: true
onTriggered: { onTriggered: {
@ -227,7 +229,7 @@ Item
stop(); stop();
callBack(1, receipt); callBack(1, receipt);
} }
else if (elapsed > 250000) else if (elapsed > 2500000)
{ {
stop(); stop();
callBack(-1, null); callBack(-1, null);

55
mix/qml/KeyValuePanel.qml

@ -82,45 +82,44 @@ ColumnLayout {
clip: true clip: true
ColumnLayout ColumnLayout
{ {
anchors.margins: 10 spacing: 0
id: colValue
anchors.top: parent.top
anchors.topMargin: 5
Repeater Repeater
{ {
id: repeaterKeyValue id: repeaterKeyValue
model: modelKeyValue model: modelKeyValue
RowLayout Row
{ {
Layout.fillWidth: true
Layout.preferredHeight: 30 Layout.preferredHeight: 30
spacing: 0 spacing: 5
Rectangle anchors.left: colValue.left
anchors.leftMargin: 5
Label
{ {
Layout.preferredWidth: columnValues.width / 2 maximumLineCount: 1
Label text: {
{ if (index >= 0 && repeaterKeyValue.model.get(index).key !== undefined)
anchors.left: parent.left return repeaterKeyValue.model.get(index).key
anchors.leftMargin: 10 else
text: { return ""
if (index >= 0 && repeaterKeyValue.model.get(index).key !== undefined)
return repeaterKeyValue.model.get(index).key
else
return ""
}
} }
} }
Rectangle Label
{ {
Layout.preferredWidth: columnValues.width / 2 - 10 text: "="
Label }
{
anchors.right: parent.right Label
anchors.rightMargin: 10 {
text: { maximumLineCount: 1
if (index >= 0 && repeaterKeyValue.model.get(index).value !== undefined) text: {
return repeaterKeyValue.model.get(index).value if (index >= 0 && repeaterKeyValue.model.get(index).value !== undefined)
else return repeaterKeyValue.model.get(index).value
return "" else
} return ""
} }
} }
} }

2
mix/qml/PackagingStep.qml

@ -20,6 +20,7 @@ Rectangle {
property alias lastDeployDate: lastDeployLabel.text property alias lastDeployDate: lastDeployLabel.text
property string deploymentId property string deploymentId
property string packageDir property string packageDir
signal packaged
function show() function show()
{ {
@ -107,6 +108,7 @@ Rectangle {
{ {
NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses); NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses);
projectModel.saveProject() projectModel.saveProject()
root.packaged()
} }
} }

20
mix/qml/ProjectModel.qml

@ -80,20 +80,14 @@ Item {
function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); }
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function deployProject() { NetworkDeploymentCode.deployProject(false); } function deployProject() { NetworkDeploymentCode.deployProject(false); }
function registerToUrlHint(url, callback) { NetworkDeploymentCode.registerToUrlHint(url, callback); } function registerToUrlHint(url, gasPrice, callback) { NetworkDeploymentCode.registerToUrlHint(url, gasPrice, callback); }
function formatAppUrl() { NetworkDeploymentCode.formatAppUrl(url); } function formatAppUrl() { NetworkDeploymentCode.formatAppUrl(url); }
function cleanDeploymentStatus() function cleanDeploymentStatus()
{ {
deployedScenarioIndex = 0 deployedScenarioIndex = 0
applicationUrlEth = ""
applicationUrlHttp = ""
deployBlockNumber = "" deployBlockNumber = ""
deploymentTrHashes = {} deploymentTrHashes = {}
registerContentHashTrHash = ""
registerUrlTrHash = ""
registerContentHashBlockNumber = -1
registerUrlBlockNumber = -1
deploymentAddresses = {} deploymentAddresses = {}
deploymentDir = "" deploymentDir = ""
deploymentDialog.packageStep.packageHash = "" deploymentDialog.packageStep.packageHash = ""
@ -102,6 +96,18 @@ Item {
deploymentDialog.packageStep.lastDeployDate = "" deploymentDialog.packageStep.lastDeployDate = ""
deploymentDialog.packageStep.localPackageUrl = "" deploymentDialog.packageStep.localPackageUrl = ""
saveProject() saveProject()
cleanRegisteringStatus()
}
function cleanRegisteringStatus()
{
applicationUrlEth = ""
applicationUrlHttp = ""
registerContentHashTrHash = ""
registerUrlTrHash = ""
registerContentHashBlockNumber = -1
registerUrlBlockNumber = -1
saveProject()
} }
Connections { Connections {

74
mix/qml/RegisteringStep.qml

@ -19,42 +19,58 @@ Rectangle {
id: root id: root
color: "#E3E3E3E3" color: "#E3E3E3E3"
anchors.fill: parent anchors.fill: parent
signal registered
function show() function show()
{ {
ctrRegisterLabel.calculateRegisterGas() ctrRegisterLabel.calculateRegisterGas()
applicationUrlEthCtrl.text = projectModel.applicationUrlEth if (applicationUrlHttpCtrl.text === "")
applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp
if (applicationUrlEthCtrl.text === "")
applicationUrlEthCtrl.text = projectModel.applicationUrlEth
visible = true visible = true
verificationEthUrl.text = "" verificationEthUrl.text = ""
if (projectModel.registerContentHashTrHash !== "") if (projectModel.registerContentHashTrHash !== "" && projectModel.registerContentHashBlockNumber !== -1)
{ {
worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost)
{ {
updateVerification(projectModel.registerContentHashBlockNumber, bn, trLost, verificationEthUrl) updateVerification(projectModel.registerContentHashBlockNumber, bn, trLost, verificationEthUrl, "registerHash")
}); });
} }
else if (projectModel.registerContentHashTrHash !== "" && projectModel.registerContentHashBlockNumber === -1)
verificationEthUrl.text = qsTr("waiting verifications")
verificationUrl.text = "" verificationUrl.text = ""
if (projectModel.registerUrlTrHash !== "") if (projectModel.registerUrlTrHash !== "" && projectModel.registerUrlBlockNumber !== -1)
{ {
worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost)
{ {
updateVerification(projectModel.registerUrlBlockNumber, bn, trLost, verificationUrl) updateVerification(projectModel.registerUrlBlockNumber, bn, trLost, verificationUrl, "registerUrl")
}); });
} }
else if (projectModel.registerUrlTrHash !== "" && projectModel.registerUrlBlockNumber === -1)
verificationUrl.text = qsTr("waiting verifications")
} }
function updateVerification(originbn, bn, trLost, ctrl) function updateVerification(originbn, bn, trLost, ctrl, trContext)
{ {
if (trLost.length === 0) if (trLost.length === 0)
{ {
ctrl.text = bn - originbn ctrl.text = bn - originbn
ctrl.text += qsTr(" verifications") if (parseInt(bn - originbn) >= 10)
{
ctrl.color= "green"
ctrl.text= qsTr("verified")
}
else
ctrl.text += qsTr(" verifications")
} }
else else
{ {
deploymentStepChanged(trContext + qsTr(" has been invalidated.") + trLost[0] + " " + qsTr("no longer present") )
ctrl.text = qsTr("invalidated") ctrl.text = qsTr("invalidated")
} }
} }
@ -124,6 +140,7 @@ Rectangle {
{ {
id: verificationUrl id: verificationUrl
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font.italic: true
} }
} }
@ -136,7 +153,7 @@ Rectangle {
Layout.preferredWidth: col.width / 2 Layout.preferredWidth: col.width / 2
Label Label
{ {
text: qsTr("Gas to use for dapp registration") text: qsTr("Registration Cost")
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
id: ctrRegisterLabel id: ctrRegisterLabel
@ -148,9 +165,12 @@ Rectangle {
NetworkDeploymentCode.checkPathCreationCost(applicationUrlEthCtrl.text, function(pathCreationCost) NetworkDeploymentCode.checkPathCreationCost(applicationUrlEthCtrl.text, function(pathCreationCost)
{ {
var ether = QEtherHelper.createBigInt(pathCreationCost); var ether = QEtherHelper.createBigInt(pathCreationCost);
var gasTotal = ether.multiply(worker.gasPriceInt); if (deploymentDialog.deployStep.gasPrice.value)
gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); {
gasToUseDeployInput.update(); var gasTotal = ether.multiply(deploymentDialog.deployStep.gasPrice.value.toWei());
gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent);
gasToUseDeployInput.update();
}
}); });
} }
} }
@ -159,9 +179,9 @@ Rectangle {
Ether Ether
{ {
id: gasToUseDeployInput id: gasToUseDeployInput
displayUnitSelection: true displayUnitSelection: false
displayFormattedValue: true displayFormattedValue: true
edit: true edit: false
Layout.preferredWidth: 235 Layout.preferredWidth: 235
} }
} }
@ -224,6 +244,10 @@ Rectangle {
Label Label
{ {
id: verificationEthUrl id: verificationEthUrl
anchors.verticalCenter: parent.verticalCenter;
anchors.topMargin: 10
font.italic: true
font.pointSize: appStyle.absoluteSize(-1)
} }
} }
} }
@ -234,7 +258,7 @@ Rectangle {
anchors.bottomMargin: 10 anchors.bottomMargin: 10
width: parent.width width: parent.width
function registerHash(callback) function registerHash(gasPrice, callback)
{ {
var inError = []; var inError = [];
var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text); var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text);
@ -244,10 +268,11 @@ Rectangle {
inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n");
} }
if (!worker.stopForInputError(inError)) if (!worker.stopForInputError(inError))
{ {
NetworkDeploymentCode.registerDapp(ethUrl, function(){ NetworkDeploymentCode.registerDapp(ethUrl, gasPrice, function(){
projectModel.applicationUrlEth = applicationUrlEthCtrl.text projectModel.applicationUrlEth = applicationUrlEthCtrl.text
projectModel.saveProject() projectModel.saveProject()
verificationEthUrl.text = qsTr("waiting verifications")
worker.waitForTrReceipt(projectModel.registerContentHashTrHash, function(status, receipt) worker.waitForTrReceipt(projectModel.registerContentHashTrHash, function(status, receipt)
{ {
worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost)
@ -262,7 +287,7 @@ Rectangle {
} }
} }
function registerUrl() function registerUrl(gasPrice, callback)
{ {
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
{ {
@ -276,9 +301,10 @@ Rectangle {
inError.push(qsTr(applicationUrlHttpCtrl.text)); inError.push(qsTr(applicationUrlHttpCtrl.text));
if (!worker.stopForInputError(inError)) if (!worker.stopForInputError(inError))
{ {
registerToUrlHint(applicationUrlHttpCtrl.text, function(){ registerToUrlHint(applicationUrlHttpCtrl.text, gasPrice, function(){
projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text
projectModel.saveProject() projectModel.saveProject()
verificationUrl.text = qsTr("waiting verifications")
worker.waitForTrReceipt(projectModel.registerUrlTrHash, function(status, receipt) worker.waitForTrReceipt(projectModel.registerUrlTrHash, function(status, receipt)
{ {
worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost)
@ -286,6 +312,8 @@ Rectangle {
projectModel.registerUrlBlockNumber = bn projectModel.registerUrlBlockNumber = bn
projectModel.saveProject() projectModel.saveProject()
root.updateVerification(bn, bn, trLost, verificationUrl) root.updateVerification(bn, bn, trLost, verificationUrl)
root.registered()
callback()
}); });
}) })
}) })
@ -300,8 +328,12 @@ Rectangle {
width: 30 width: 30
onClicked: onClicked:
{ {
parent.registerHash(function(){ verificationEthUrl.text = ""
parent.registerUrl() verificationUrl.text = ""
projectModel.cleanRegisteringStatus()
var gasPrice = deploymentDialog.deployStep.gasPrice.toHexWei()
parent.registerHash(gasPrice, function(){
parent.registerUrl(gasPrice, function(){})
}) })
} }
} }

4
mix/qml/ScenarioLoader.qml

@ -35,7 +35,7 @@ ColumnLayout
{ {
Layout.preferredWidth: 560 Layout.preferredWidth: 560
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Layout.preferredHeight: 60 Layout.preferredHeight: 75
spacing: 0 spacing: 0
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 10 anchors.topMargin: 10
@ -88,7 +88,7 @@ ColumnLayout
color: "#cccccc" color: "#cccccc"
id: deleteImg id: deleteImg
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 6 anchors.topMargin: 7
visible: projectModel.stateListModel.count > 1 visible: projectModel.stateListModel.count > 1
MouseArea MouseArea
{ {

2
mix/qml/StatusPane.qml

@ -179,7 +179,7 @@ Rectangle {
function updateWidth() function updateWidth()
{ {
if (text.length > 80) if (text.length > 100)
width = parent.width - 10 width = parent.width - 10
else else
width = undefined width = undefined

3
mix/qml/WebPreview.qml

@ -272,7 +272,8 @@ Item {
Button Button
{ {
height: 28 height: 22
width: 22
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
action: expressionAction action: expressionAction
iconSource: "qrc:/qml/img/console.png" iconSource: "qrc:/qml/img/console.png"

39
mix/qml/js/NetworkDeployment.js

@ -32,11 +32,10 @@ function deployProject(force) {
deploymentDialog.open(); deploymentDialog.open();
} }
function deployContracts(gas, callback) function deployContracts(gas, gasPrice, callback)
{ {
deploymentGas = gas; deploymentGas = gas;
var jsonRpcUrl = "http://127.0.0.1:8080"; deploymentGasPrice = gasPrice
console.log("Deploying to " + jsonRpcUrl);
deploymentStarted(); deploymentStarted();
var ctrAddresses = {}; var ctrAddresses = {};
@ -79,10 +78,7 @@ function checkPathCreationCost(ethUrl, callBack)
} }
} }
else else
{
deploymentStepChanged(qsTr("Your Dapp can be registered here."));
callBack((dappUrl.length - 1) * (deploymentDialog.registerStep.ownedRegistrarDeployGas + deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); callBack((dappUrl.length - 1) * (deploymentDialog.registerStep.ownedRegistrarDeployGas + deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.registerStep.ownedRegistrarSetContentHashGas);
}
}); });
} }
@ -140,6 +136,7 @@ function getFunction(ctrName, functionId)
} }
var deploymentGas var deploymentGas
var deploymentGasPrice
var trRealIndex = -1 var trRealIndex = -1
function executeTr(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack) function executeTr(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack)
{ {
@ -153,14 +150,14 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack)
else else
{ {
var gasCost = clientModel.toHex(deploymentGas[trRealIndex]); var gasCost = clientModel.toHex(deploymentGas[trRealIndex]);
var rpcParams = { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost }; var rpcParams = { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "gasPrice": deploymentGasPrice };
var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses); var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses);
var encodedParams = clientModel.encodeParams(params, contractFromToken(tr.contractId), tr.functionId); var encodedParams = clientModel.encodeParams(params, contractFromToken(tr.contractId), tr.functionId);
if (tr.contractId === tr.functionId) if (tr.contractId === tr.functionId)
rpcParams.code = codeModel.contracts[tr.contractId].codeHex + encodedParams.join(""); rpcParams.code = codeModel.contracts[tr.contractId].codeHex + encodedParams.join("");
else else
rpcParams.data = func.hash + encodedParams.join(""); rpcParams.data = "0x" + func.qhash() + encodedParams.join("");
var requests = [{ var requests = [{
jsonrpc: "2.0", jsonrpc: "2.0",
@ -214,13 +211,9 @@ function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, trHashes, c
{ {
blockIndex++ blockIndex++
if (blockIndex < state.blocks.count) if (blockIndex < state.blocks.count)
{
executeTr(blockIndex, 0, state, ctrAddresses, trHashes, callBack); executeTr(blockIndex, 0, state, ctrAddresses, trHashes, callBack);
}
else else
{
callBack(); callBack();
}
} }
} }
@ -298,16 +291,17 @@ function packageDapp(addresses)
deploymentDialog.packageStep.packageBase64 = packageRet[1]; deploymentDialog.packageStep.packageBase64 = packageRet[1];
deploymentDialog.packageStep.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; deploymentDialog.packageStep.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0];
deploymentDialog.packageStep.lastDeployDate = date deploymentDialog.packageStep.lastDeployDate = date
deploymentComplete() deploymentStepChanged(qsTr("Dapp is Packaged"))
} }
function registerDapp(url, callback) function registerDapp(url, gasPrice, callback)
{ {
deploymentGasPrice = gasPrice
deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkEthPath(url, false, function (success) { checkEthPath(url, false, function (success) {
if (!success) if (!success)
return; return;
deploymentComplete(); deploymentStepChanged(qsTr("Dapp has been registered. Please wait for verifications."));
if (callback) if (callback)
callback() callback()
}); });
@ -446,7 +440,7 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly)
requests.push({ requests.push({
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_sendTransaction", method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ], params: [ { "from": deploymentDialog.worker.currentAccount, "gasPrice": deploymentGasPrice, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -468,7 +462,7 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly)
//setRegister() //setRegister()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_sendTransaction", method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + newCtrAddress } ], params: [ { "from": deploymentDialog.worker.currentAccount, "gasPrice": deploymentGasPrice, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + newCtrAddress } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -501,7 +495,7 @@ function reserve(registrar, callBack)
//reserve() //reserve()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_sendTransaction", method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ], params: [ { "from": deploymentDialog.worker.currentAccount, "gasPrice": deploymentGasPrice, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -524,7 +518,7 @@ function registerContentHash(registrar, callBack)
//setContent() //setContent()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_sendTransaction", method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageStep.packageHash } ], params: [ { "from": deploymentDialog.worker.currentAccount, "gasPrice": deploymentGasPrice, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageStep.packageHash } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -533,9 +527,10 @@ function registerContentHash(registrar, callBack)
}); });
} }
function registerToUrlHint(url, callback) function registerToUrlHint(url, gasPrice, callback)
{ {
console.log("register url " + deploymentDialog.packageStep.packageHash + " " + url) console.log("register url " + deploymentDialog.packageStep.packageHash + " " + url)
deploymentGasPrice = gasPrice
deploymentStepChanged(qsTr("Registering application Resources...")) deploymentStepChanged(qsTr("Registering application Resources..."))
urlHintAddress(function(urlHint){ urlHintAddress(function(urlHint){
var requests = []; var requests = [];
@ -545,13 +540,13 @@ function registerToUrlHint(url, callback)
//urlHint => suggestUrl //urlHint => suggestUrl
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_sendTransaction", method: "eth_sendTransaction",
params: [ { "to": '0x' + urlHint, "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageStep.packageHash + paramUrlHttp } ], params: [ { "to": '0x' + urlHint, "gasPrice": deploymentGasPrice, "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageStep.packageHash + paramUrlHttp } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
projectModel.registerUrlTrHash = JSON.parse(response)[0].result projectModel.registerUrlTrHash = JSON.parse(response)[0].result
deploymentComplete(); deploymentStepChanged(qsTr("Dapp resources has been registered. Please wait for verifications."));
if (callback) if (callback)
callback() callback()
}); });

3
mix/qml/js/TransactionHelper.js

@ -33,7 +33,8 @@ function rpcCall(requests, callBack, error)
{ {
var errorText = qsTr("Unable to initiate request to the live network. Please verify your ethereum node is up.") + qsTr(" Error status: ") + httpRequest.status; var errorText = qsTr("Unable to initiate request to the live network. Please verify your ethereum node is up.") + qsTr(" Error status: ") + httpRequest.status;
console.log(errorText); console.log(errorText);
error(errorText); if (error)
error(errorText);
} }
else else
{ {

46
test/libsolidity/SolidityWallet.cpp

@ -116,7 +116,7 @@ contract multiowned {
} }
// Replaces an owner `_from` with another `_to`. // Replaces an owner `_from` with another `_to`.
function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data, block.number)) external { function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external {
if (isOwner(_to)) return; if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)]; uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return; if (ownerIndex == 0) return;
@ -128,7 +128,7 @@ contract multiowned {
OwnerChanged(_from, _to); OwnerChanged(_from, _to);
} }
function addOwner(address _owner) onlymanyowners(sha3(msg.data, block.number)) external { function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
if (isOwner(_owner)) return; if (isOwner(_owner)) return;
clearPending(); clearPending();
@ -142,7 +142,7 @@ contract multiowned {
OwnerAdded(_owner); OwnerAdded(_owner);
} }
function removeOwner(address _owner) onlymanyowners(sha3(msg.data, block.number)) external { function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
uint ownerIndex = m_ownerIndex[uint(_owner)]; uint ownerIndex = m_ownerIndex[uint(_owner)];
if (ownerIndex == 0) return; if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return; if (m_required > m_numOwners - 1) return;
@ -154,7 +154,7 @@ contract multiowned {
OwnerRemoved(_owner); OwnerRemoved(_owner);
} }
function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data, block.number)) external { function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external {
if (_newRequired > m_numOwners) return; if (_newRequired > m_numOwners) return;
m_required = _newRequired; m_required = _newRequired;
clearPending(); clearPending();
@ -275,16 +275,17 @@ contract daylimit is multiowned {
// METHODS // METHODS
// constructor - just records the present day's index. // constructor - stores initial daily limit and records the present day's index.
function daylimit() { function daylimit(uint _limit) {
m_dailyLimit = _limit;
m_lastDay = today(); m_lastDay = today();
} }
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data, block.number)) external { function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external {
m_dailyLimit = _newLimit; m_dailyLimit = _newLimit;
} }
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
function resetSpentToday() onlymanyowners(sha3(msg.data, block.number)) external { function resetSpentToday() onlymanyowners(sha3(msg.data)) external {
m_spentToday = 0; m_spentToday = 0;
} }
@ -354,12 +355,14 @@ contract Wallet is multisig, multiowned, daylimit {
// METHODS // METHODS
// constructor - just pass on the owner array to the multiowned. // constructor - just pass on the owner array to the multiowned and
function Wallet(address[] _owners, uint _required) multiowned(_owners, _required) { // the limit to daylimit
function Wallet(address[] _owners, uint _required, uint _daylimit)
multiowned(_owners, _required) daylimit(_daylimit) {
} }
// kills the contract sending everything to `_to`. // kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data, block.number)) external { function kill(address _to) onlymanyowners(sha3(msg.data)) external {
suicide(_to); suicide(_to);
} }
@ -424,7 +427,12 @@ static unique_ptr<bytes> s_compiledWallet;
class WalletTestFramework: public ExecutionFramework class WalletTestFramework: public ExecutionFramework
{ {
protected: protected:
void deployWallet(u256 const& _value = 0, vector<u256> const& _owners = vector<u256>{}, u256 _required = 1) void deployWallet(
u256 const& _value = 0,
vector<u256> const& _owners = vector<u256>{},
u256 _required = 1,
u256 _dailyLimit = 0
)
{ {
if (!s_compiledWallet) if (!s_compiledWallet)
{ {
@ -434,7 +442,7 @@ protected:
ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed"); ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed");
s_compiledWallet.reset(new bytes(m_compiler.getBytecode("Wallet"))); s_compiledWallet.reset(new bytes(m_compiler.getBytecode("Wallet")));
} }
bytes args = encodeArgs(u256(0x40), _required, u256(_owners.size()), _owners); bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners);
sendMessage(*s_compiledWallet + args, true, _value); sendMessage(*s_compiledWallet + args, true, _value);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }
@ -519,7 +527,7 @@ BOOST_AUTO_TEST_CASE(initial_owners)
u256("0x0000000000000000000000004c9113886af165b2de069d6e99430647e94a9fff"), u256("0x0000000000000000000000004c9113886af165b2de069d6e99430647e94a9fff"),
u256("0x0000000000000000000000003fb1cd2cd96c6d5c0b5eb3322d807b34482481d4") u256("0x0000000000000000000000003fb1cd2cd96c6d5c0b5eb3322d807b34482481d4")
}; };
deployWallet(0, owners, 4); deployWallet(0, owners, 4, 2);
BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8))); BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8)));
BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true)); BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
for (u256 const& owner: owners) for (u256 const& owner: owners)
@ -554,7 +562,9 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
BOOST_AUTO_TEST_CASE(daylimit) BOOST_AUTO_TEST_CASE(daylimit)
{ {
deployWallet(200); deployWallet(200);
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(0)));
BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(100)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(100)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(100)));
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
@ -585,6 +595,14 @@ BOOST_AUTO_TEST_CASE(daylimit)
BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 90); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 90);
} }
BOOST_AUTO_TEST_CASE(daylimit_constructor)
{
deployWallet(200, {}, 1, 20);
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(20)));
BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(30)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(30)));
}
//@todo test data calls //@todo test data calls
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save