Browse Source

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

cl-refactor
Paweł Bylica 10 years ago
parent
commit
2bd892c1fc
  1. 59
      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. 12
      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. 130
      mix/qml/DeployContractStep.qml
  34. 21
      mix/qml/DeploymentDialog.qml
  35. 164
      mix/qml/DeploymentDialogSteps.qml
  36. 6
      mix/qml/DeploymentWorker.qml
  37. 29
      mix/qml/KeyValuePanel.qml
  38. 2
      mix/qml/PackagingStep.qml
  39. 20
      mix/qml/ProjectModel.qml
  40. 64
      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. 1
      mix/qml/js/TransactionHelper.js
  46. 46
      test/libsolidity/SolidityWallet.cpp

59
alethzero/MainWin.cpp

@ -189,6 +189,9 @@ Main::Main(QWidget *parent) :
#endif
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;
auto block = CanonBlockChain<Ethash>::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain<Ethash>::genesis().hash() << endl;
@ -375,10 +378,17 @@ NetworkPreferences Main::netPrefs() const
publicIP.clear();
}
NetworkPreferences ret;
if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
ret = NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
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()
@ -773,6 +783,30 @@ void Main::writeSettings()
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
{
while (true)
@ -849,8 +883,7 @@ void Main::readSettings(bool _skipGeometry)
ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString();
ui->usePrivate->setChecked(m_privateChain.size());
setPrivateChain(s.value("privateChain", "").toString());
ui->verbosity->setValue(s.value("verbosity", 1).toInt());
#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()
{
QString pc;
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)));
if (m_privateChain.isEmpty())
{
if (ui->usePrivate->isChecked())
ui->usePrivate->setChecked(false);
else
// was cancelled.
bool ok;
pc = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)), &ok);
if (!ok)
return;
}
}
else
m_privateChain.clear();
on_killBlockchain_triggered();
setPrivateChain(pc);
}
void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); }
@ -2012,7 +2039,7 @@ void Main::on_net_triggered()
{
web3()->setIdealPeerCount(ui->idealPeers->value());
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();
ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode()));

2
alethzero/MainWin.h

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

70
eth/main.cpp

@ -121,8 +121,13 @@ void help()
<< "Usage eth [OPTIONS]" << endl
<< "Options:" << endl << 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
#if ETH_JSCONSOLE || !ETH_TRUE
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#endif
#if ETH_JSONRPC || !ETH_TRUE
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << 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
<< " --password <password> Give a password for a private key." << 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
<< "Client transacting:" << 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
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << 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
<< " --no-discovery Disable Node discovery. (experimental)" << endl
<< " --pin Only connect to required (trusted) peers. (experimental)" << endl
<< " --no-discovery Disable Node discovery." << endl
<< " --pin Only connect to required (trusted) peers." << endl
// << " --require-peers <peers.json> List of required (trusted) peers. (experimental)" << endl
<< endl;
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,--version Show the version 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);
}
@ -1068,8 +1069,8 @@ int main(int argc, char** argv)
/// Operating mode.
OperationMode mode = OperationMode::Node;
string dbPath;
unsigned prime = 0;
bool yesIReallyKnowWhatImDoing = false;
// unsigned prime = 0;
// bool yesIReallyKnowWhatImDoing = false;
/// File name for import/export.
string filename;
@ -1083,10 +1084,14 @@ int main(int argc, char** argv)
/// General params for Node operation
NodeMode nodeMode = NodeMode::Full;
bool interactive = false;
#if ETH_JSONRPC
#if ETH_JSONRPC || !ETH_TRUE
int jsonrpc = -1;
#endif
string jsonAdmin;
string genesisJSON;
dev::eth::Network releaseNetwork = c_network;
string privateChain;
bool upnp = true;
WithExisting withExisting = WithExisting::Trust;
string sentinel;
@ -1192,7 +1197,7 @@ int main(int argc, char** argv)
mode = OperationMode::Export;
filename = argv[++i];
}
else if (arg == "--prime" && i + 1 < argc)
/* else if (arg == "--prime" && i + 1 < argc)
try
{
prime = stoi(argv[++i]);
@ -1204,7 +1209,7 @@ int main(int argc, char** argv)
}
else if (arg == "--yes-i-really-know-what-im-doing")
yesIReallyKnowWhatImDoing = true;
else if (arg == "--sentinel" && i + 1 < argc)
*/ else if (arg == "--sentinel" && i + 1 < argc)
sentinel = argv[++i];
else if (arg == "--mine-on-wrong-chain")
mineOnWrongChain = true;
@ -1253,6 +1258,15 @@ int main(int argc, char** argv)
cerr << "Bad " << arg << " option: " << argv[i] << endl;
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")
withExisting = WithExisting::Kill;
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)
dbPath = argv[++i];
else if (arg == "--genesis-nonce" && i + 1 < argc)
else if (arg == "--genesis-json" && i + 1 < argc)
{
try
{
CanonBlockChain<Ethash>::setGenesisNonce(Nonce(argv[++i]));
genesisJSON = contentsString(argv[++i]);
}
catch (...)
{
@ -1318,6 +1332,10 @@ int main(int argc, char** argv)
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)
{
try
@ -1412,9 +1430,9 @@ int main(int argc, char** argv)
pinning = true;
else if (arg == "-f" || arg == "--force-mining")
forceMining = true;
else if (arg == "-i" || arg == "--interactive")
else if (arg == "--old-interactive")
interactive = true;
#if ETH_JSONRPC
#if ETH_JSONRPC || !ETH_TRUE
else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
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)
jsonAdmin = argv[++i];
#endif
#if ETH_JSCONSOLE
else if (arg == "--console")
#if ETH_JSCONSOLE || !ETH_TRUE
else if (arg == "-i" || arg == "--interactive" || arg == "--console")
useConsole = true;
#endif
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)
{
cout << EthGrayBold "(++)Ethereum" EthReset << endl;
@ -1529,8 +1554,9 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
netPrefs.discovery = !disableDiscovery;
netPrefs.pin = pinning;
netPrefs.discovery = privateChain.empty() && !disableDiscovery;
netPrefs.pin = pinning || !privateChain.empty();
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
dev::WebThreeDirect web3(
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;
return 0;
}
/*
if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing)
{
auto pd = contents(getDataDir() + "primes");
@ -1652,7 +1678,7 @@ int main(int argc, char** argv)
primes.insert(prime);
writeFile(getDataDir() + "primes", rlp(primes));
}
*/
if (keyManager.exists())
{
if (masterPassword.empty() || !keyManager.load(masterPassword))

6
ethminer/MinerAux.h

@ -398,6 +398,12 @@ private:
cdebug << genesis.boundary();
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; });
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;
}
#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)
{
s.commitToMine(_bc);

2
libdevcore/Common.cpp

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

2
libdevcore/Exceptions.h

@ -56,7 +56,7 @@ DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(NoNetworking);
DEV_SIMPLE_EXCEPTION(NoUPnPDevice);
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(Overflow);
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).
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(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 ret;
#ifdef ETH_HAVE_SECP256K1
bytes o(65);
int pubkeylen;
if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64]))
return Public();
return FixedHash<64>(o.data()+1, Public::ConstructFromPointer);
ret = FixedHash<64>(o.data() + 1, Public::ConstructFromPointer);
#else
return s_secp256k1pp.recover(_sig, _message.ref());
ret = s_secp256k1pp.recover(_sig, _message.ref());
#endif
if (ret == c_zeroKey)
return Public();
return ret;
}
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
p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
if (p.identity)
return Public();
m_curve.EncodePoint(recoveredbytes, p, false);
}
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_number = _parent.m_number + 1;
m_parentHash = _parent.m_hash;
m_gasLimit = selectGasLimit(_parent);
m_gasUsed = 0;
m_difficulty = calculateDifficulty(_parent);
m_parentHash = _parent.m_hash;
}
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
{
if (!m_parentHash)
return c_genesisGasLimit;
static const u256 c_gasFloorTarget = 3141592;
if (!m_number)
throw GenesisBlockCannotBeCalculated();
else
// target minimum of 3141592
if (_parent.m_gasLimit < c_genesisGasLimit)
return min<u256>(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1);
if (_parent.m_gasLimit < c_gasFloorTarget)
return min<u256>(c_gasFloorTarget, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1);
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
{
if (!m_parentHash)
return (u256)c_genesisDifficulty;
if (!m_number)
throw GenesisBlockCannotBeCalculated();
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)));
}

1
libethcore/BlockInfo.h

@ -53,6 +53,7 @@ enum BlockDataType
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
DEV_SIMPLE_EXCEPTION(GenesisBlockCannotBeCalculated);
/** @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

17
libethcore/Common.cpp

@ -29,6 +29,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "Params.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
@ -51,11 +52,23 @@ const unsigned c_databaseVersionModifier = 0;
#endif
#if ETH_FRONTIER
Network const c_network = Network::Frontier;
Network c_network = resetNetwork(Network::Frontier);
#else
Network const c_network = Network::Olympic;
Network c_network = resetNetwork(Network::Olympic);
#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);
vector<pair<u256, string>> const& units()

4
libethcore/Common.h

@ -50,7 +50,9 @@ enum class Network
Frontier = 1,
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.
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)
{
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_nonce = sol.nonce;
if (!m_sealing.preVerify())
return false;
RLPStream ret;
m_sealing.streamRLP(ret);
_f(ret.out());

2
libethcore/Miner.h

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

14
libethcore/Params.cpp

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

15
libethcore/Params.h

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

2
libethcore/Sealer.h

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

34
libethereum/BlockChain.cpp

@ -147,7 +147,12 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
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.
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.
m_genesisBlock = _genesisBlock;
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.
upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion)
if (openDatabase(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p);
}
@ -169,7 +175,7 @@ BlockChain::~BlockChain()
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 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))
{
BlockInfo gb(m_genesisBlock);
// 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();
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()
{
cnote << "Closing blockchain DB";
// Not thread safe...
delete m_extrasDB;
delete m_blocksDB;
m_lastBlockHash = m_genesisHash;
m_lastBlockNumber = 0;
m_details.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)
@ -293,7 +310,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
m_lastBlockHash = genesisHash();
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()));
@ -586,9 +603,11 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
#endif
}
#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());
}
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?
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.resetCurrent();
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();
/// Attempt a database re-open.
void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust) { close(); open(_path, _we); }
/// Reopen everything.
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.
/// To be called from main loop every 100ms or so.
@ -291,7 +291,11 @@ public:
protected:
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();
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::string m_dbPath;
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
{
VerifiedBlockRef res;
BlockHeader h;
try
{
BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h = BlockHeader(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h.verifyInternals(_block);
if ((_ir & ImportRequirements::Parent) != 0)
{
@ -412,6 +418,7 @@ public:
ex << errinfo_phase(1);
ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes());
ex << errinfo_extraData(h.extraData());
if (_onBad)
_onBad(ex);
throw;
@ -422,9 +429,10 @@ public:
if (_ir && ImportRequirements::UncleBasic)
for (auto const& uncle: r[2])
{
BlockHeader h;
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)
{
@ -432,6 +440,7 @@ public:
ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes());
ex << errinfo_extraData(h.extraData());
if (_onBad)
_onBad(ex);
throw;

54
libethereum/CanonBlockChain.cpp

@ -38,18 +38,23 @@ using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1
std::unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
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):
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()
{
RLPStream block(3);
@ -63,8 +68,35 @@ bytes CanonBlockChain<Ethash>::createGenesisBlock()
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)
<< 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);
return block.out();
@ -78,12 +110,14 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
{
js::mValue 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;
if (account.second.get_obj().count("wei"))
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;
if (account.second.get_obj().count("code"))
{
@ -97,17 +131,17 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
return s_ret;
}
void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json)
void CanonBlockChain<Ethash>::setGenesis(std::string const& _json)
{
WriteGuard l(x_genesis);
s_genesisStateJSON = _json;
s_genesis.reset();
}
void CanonBlockChain<Ethash>::setGenesisNonce(Nonce const& _n)
void CanonBlockChain<Ethash>::forceGenesisExtraData(bytes const& _genesisExtraData)
{
WriteGuard l(x_genesis);
s_nonce = _n;
s_genesisExtraData = _genesisExtraData;
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() {}
/// Reopen everything.
virtual void reopen(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
/// @returns the genesis block header.
static Ethash::BlockHeader const& genesis();
@ -89,18 +92,13 @@ public:
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
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.
/// @TODO implement.
/// @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 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:
/// Static genesis info and its lock.
@ -108,6 +106,7 @@ private:
static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce;
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"]["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(got);
DEV_HINT_ERRINFO_HASH(required_LogBloom);
@ -316,7 +327,7 @@ void Client::doneWorking()
}
}
void Client::killChain()
void Client::reopenChain(WithExisting _we)
{
bool wasMining = isMining();
if (wasMining)
@ -337,11 +348,11 @@ void Client::killChain()
m_working = State();
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
bc().reopen(Defaults::dbPath(), WithExisting::Kill);
bc().reopen(_we);
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), _we);
m_preMine = bc().genesisState(m_stateDB);
m_postMine = State(m_stateDB);
m_postMine = m_preMine;
}
if (auto h = m_host.lock())
@ -450,6 +461,14 @@ void Client::setShouldPrecomputeDAG(bool _precompute)
sealEngine()->setOption("precomputeDAG", _precompute ? trueBytes: falseBytes);
}
void Client::setTurboMining(bool _enable)
{
m_turboMining = _enable;
sealEngine()->setSealer("opencl");
if (isMining())
startMining();
}
bool Client::isMining() const
{
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);
}
void Client::restartMining()
void Client::resyncStateFromChain()
{
// RESTART MINING
@ -639,7 +658,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
m_tq.dropGood(t);
}
onNewBlocks(_ir.liveBlocks, changeds);
restartMining();
resyncStateFromChain();
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
{
public:
/// New-style Constructor.
/// Any final derived class's constructor should make sure they call init().
explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
/// Destructor.
virtual ~Client();
@ -139,7 +135,7 @@ public:
/// Are we allowed to GPU mine?
bool turboMining() const { return m_turboMining; }
/// 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
void setShouldPrecomputeDAG(bool _precompute);
@ -180,7 +176,9 @@ public:
/// Clears pending transactions. Just for debug use.
void clearPending();
/// 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.
void retryUnknown() { m_bq.retryAllUnknown(); }
/// Get a report of activity.
@ -199,6 +197,10 @@ public:
SealEngineFace* sealEngine() const { return m_sealEngine.get(); }
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.
/// Must be called in the constructor of the finally derived class.
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);
/// Called after processing blocks by onChainChanged(_ir)
void restartMining();
void resyncStateFromChain();
/// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue().
@ -342,13 +344,8 @@ public:
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
):
Client(_gpForAdoption),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; })
SpecialisedClient(_gpForAdoption, _dbPath, _forceAction)
{
m_sealEngine = std::shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSealGenerated([=](bytes const& header){
this->submitSealed(header);
});
init(_host, _dbPath, _forceAction, _networkId);
}
@ -358,10 +355,24 @@ public:
CanonBlockChain<Sealer> const& blockChain() const { return m_bc; }
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 const& bc() const override { return m_bc; }
protected:
private:
CanonBlockChain<Sealer> m_bc; ///< Maintains block database.
};
@ -375,9 +386,11 @@ public:
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
): SpecialisedClient<Ethash>(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {}
virtual ~EthashClient() { stopWorking(); }
):
SpecialisedClient<Ethash>(_gpForAdoption, _dbPath, _forceAction)
{
init(_host, _dbPath, _forceAction, _networkId);
}
/// 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.
@ -389,10 +402,6 @@ public:
* @return true if the solution was indeed valid and accepted.
*/
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; }
};
}

12
libethereum/GenesisInfo.cpp

@ -24,6 +24,15 @@
std::string const dev::eth::c_genesisInfo =
R"ETHEREUM(
{
"nonce": "0x000000000000002a",
"difficulty": "0x20000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2FEFD8",
"alloc": {
"0000000000000000000000000000000000000001": { "wei": "1" },
"0000000000000000000000000000000000000002": { "wei": "1" },
"0000000000000000000000000000000000000003": { "wei": "1" },
@ -35,6 +44,7 @@ R"ETHEREUM(
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }
}
}
)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_block = boost::error_info<struct tag_block, bytes>;
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>;

2
libwebthree/WebThree.cpp

@ -53,7 +53,7 @@ WebThreeDirect::WebThreeDirect(
if (_interfaces.count("eth"))
{
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"))

2
mix/QBigInt.h

@ -82,6 +82,8 @@ public:
BigIntVariant internalValue() const { return m_internalValue; }
/// @returns a string representation of the big integer used. Invokable from QML.
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.
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()); }

2
mix/QFunctionDefinition.h

@ -55,6 +55,8 @@ public:
FixedHash<4> hash() const { return m_hash; }
/// Get the full hash of this function declaration on the contract ABI.
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:
int m_index;

1
mix/qml/Block.qml

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

54
mix/qml/BlockChain.qml

@ -117,47 +117,7 @@ ColumnLayout {
RowLayout
{
id: header
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
}
Layout.preferredHeight: 10
}
Rectangle
@ -178,18 +138,6 @@ ColumnLayout {
width: parent.width
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
{
id: blockChainRepeater

130
mix/qml/DeployContractStep.qml

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

21
mix/qml/DeploymentDialog.qml

@ -22,6 +22,7 @@ Dialog {
property alias packageStep: packageStep
property alias registerStep: registerStep
property alias worker: worker
property alias steps: steps
function close()
{
@ -52,15 +53,31 @@ Dialog {
anchors.fill: parent
anchors.margins: 10
RowLayout
Rectangle
{
id: explanation
Layout.preferredWidth: parent.width - 50
Layout.preferredHeight: 50
color: "transparent"
Label
{
id: info
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
}
}
}

164
mix/qml/DeploymentDialogSteps.qml

@ -26,13 +26,55 @@ Rectangle {
selected(step)
}
function reset()
{
for (var k in deployLogs.logs)
{
deployLogs.logs[k] = ""
}
deployLogs.switchLogs()
refreshCurrent()
}
border.color: "#cccccc"
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
{
anchors.fill: parent
anchors.margins: 1
spacing: 0
Repeater
{
id: menu
@ -45,7 +87,7 @@ Rectangle {
{
step: 2,
type:"package",
label: qsTr("Package files")
label: qsTr("Package Dapp")
},
{
step: 3,
@ -70,6 +112,7 @@ Rectangle {
labelContainer.state = "selected"
sel = index
itemClicked(menu.model[index].type)
deployLogs.switchLogs()
}
function unselect()
@ -136,60 +179,58 @@ Rectangle {
}
Connections {
target: projectModel
onDeploymentStarted: log.text = log.text + qsTr("Running deployment...") + "\n"
onDeploymentError: log.text = log.text + error + "\n"
onDeploymentComplete: log.text = log.text + qsTr("Deployment complete") + "\n"
onDeploymentStepChanged: log.text = log.text + message + "\n"
}
property var logs: ({})
id: deployLogs
Rectangle
function switchLogs()
{
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#cccccc"
if (root.sel)
{
if (!logs[root.sel])
logs[root.sel] = ""
log.text = logs[root.sel]
}
}
RowLayout
{
anchors.horizontalCenter: parent.horizontalCenter
Layout.preferredHeight: 20
anchors.left: parent.left
anchors.leftMargin: 2
Button
target: projectModel
onDeploymentStarted:
{
Layout.preferredHeight: 22
Layout.preferredWidth: 22
action: clearAction
iconSource: "qrc:/qml/img/cleariconactive.png"
if (!logs[root.sel])
logs[root.sel] = ""
logs[root.sel] = logs[root.sel] + qsTr("Running deployment...") + "\n"
log.text = logs[root.sel]
}
Action {
id: clearAction
enabled: log.text !== ""
tooltip: qsTr("Clear")
onTriggered: {
log.text = ""
}
onDeploymentError:
{
if (!logs[root.sel])
logs[root.sel] = ""
logs[root.sel] = logs[root.sel] + error + "\n"
log.text = logs[root.sel]
}
Button
onDeploymentComplete:
{
Layout.preferredHeight: 22
text: qsTr("Clear Deployment")
action: clearDeployAction
if (!logs[root.sel])
logs[root.sel] = ""
logs[root.sel] = logs[root.sel] + qsTr("Deployment complete") + "\n"
log.text = logs[root.sel]
}
Action {
id: clearDeployAction
onTriggered: {
worker.forceStopPooling()
fileIo.deleteDir(projectModel.deploymentDir)
projectModel.cleanDeploymentStatus()
root.refreshCurrent()
log.text = ""
onDeploymentStepChanged:
{
if (!logs[root.sel])
logs[root.sel] = ""
logs[root.sel] = logs[root.sel] + message + "\n"
log.text = logs[root.sel]
}
}
Rectangle
{
Layout.fillWidth: true
Layout.preferredHeight: 2
color: "#cccccc"
}
ScrollView
@ -205,6 +246,47 @@ Rectangle {
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;
requests = [];
accounts = []
for (var k in ids)
{
requests.push({
@ -52,6 +53,7 @@ Item
TransactionHelper.rpcCall(requests, function (request, response){
var balanceRet = JSON.parse(response);
balances = {}
for (var k in balanceRet)
{
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
@ -206,7 +208,7 @@ Item
property var callBack
property int elapsed
property string hash
interval: 500
interval: 2000
running: false
repeat: true
onTriggered: {
@ -227,7 +229,7 @@ Item
stop();
callBack(1, receipt);
}
else if (elapsed > 250000)
else if (elapsed > 2500000)
{
stop();
callBack(-1, null);

29
mix/qml/KeyValuePanel.qml

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

2
mix/qml/PackagingStep.qml

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

20
mix/qml/ProjectModel.qml

@ -80,20 +80,14 @@ Item {
function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); }
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
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 cleanDeploymentStatus()
{
deployedScenarioIndex = 0
applicationUrlEth = ""
applicationUrlHttp = ""
deployBlockNumber = ""
deploymentTrHashes = {}
registerContentHashTrHash = ""
registerUrlTrHash = ""
registerContentHashBlockNumber = -1
registerUrlBlockNumber = -1
deploymentAddresses = {}
deploymentDir = ""
deploymentDialog.packageStep.packageHash = ""
@ -102,6 +96,18 @@ Item {
deploymentDialog.packageStep.lastDeployDate = ""
deploymentDialog.packageStep.localPackageUrl = ""
saveProject()
cleanRegisteringStatus()
}
function cleanRegisteringStatus()
{
applicationUrlEth = ""
applicationUrlHttp = ""
registerContentHashTrHash = ""
registerUrlTrHash = ""
registerContentHashBlockNumber = -1
registerUrlBlockNumber = -1
saveProject()
}
Connections {

64
mix/qml/RegisteringStep.qml

@ -19,42 +19,58 @@ Rectangle {
id: root
color: "#E3E3E3E3"
anchors.fill: parent
signal registered
function show()
{
ctrRegisterLabel.calculateRegisterGas()
applicationUrlEthCtrl.text = projectModel.applicationUrlEth
if (applicationUrlHttpCtrl.text === "")
applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp
if (applicationUrlEthCtrl.text === "")
applicationUrlEthCtrl.text = projectModel.applicationUrlEth
visible = true
verificationEthUrl.text = ""
if (projectModel.registerContentHashTrHash !== "")
if (projectModel.registerContentHashTrHash !== "" && projectModel.registerContentHashBlockNumber !== -1)
{
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 = ""
if (projectModel.registerUrlTrHash !== "")
if (projectModel.registerUrlTrHash !== "" && projectModel.registerUrlBlockNumber !== -1)
{
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)
{
ctrl.text = bn - originbn
if (parseInt(bn - originbn) >= 10)
{
ctrl.color= "green"
ctrl.text= qsTr("verified")
}
else
ctrl.text += qsTr(" verifications")
}
else
{
deploymentStepChanged(trContext + qsTr(" has been invalidated.") + trLost[0] + " " + qsTr("no longer present") )
ctrl.text = qsTr("invalidated")
}
}
@ -124,6 +140,7 @@ Rectangle {
{
id: verificationUrl
anchors.verticalCenter: parent.verticalCenter
font.italic: true
}
}
@ -136,7 +153,7 @@ Rectangle {
Layout.preferredWidth: col.width / 2
Label
{
text: qsTr("Gas to use for dapp registration")
text: qsTr("Registration Cost")
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
id: ctrRegisterLabel
@ -148,9 +165,12 @@ Rectangle {
NetworkDeploymentCode.checkPathCreationCost(applicationUrlEthCtrl.text, function(pathCreationCost)
{
var ether = QEtherHelper.createBigInt(pathCreationCost);
var gasTotal = ether.multiply(worker.gasPriceInt);
if (deploymentDialog.deployStep.gasPrice.value)
{
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
{
id: gasToUseDeployInput
displayUnitSelection: true
displayUnitSelection: false
displayFormattedValue: true
edit: true
edit: false
Layout.preferredWidth: 235
}
}
@ -224,6 +244,10 @@ Rectangle {
Label
{
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
width: parent.width
function registerHash(callback)
function registerHash(gasPrice, callback)
{
var inError = [];
var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text);
@ -245,9 +269,10 @@ Rectangle {
}
if (!worker.stopForInputError(inError))
{
NetworkDeploymentCode.registerDapp(ethUrl, function(){
NetworkDeploymentCode.registerDapp(ethUrl, gasPrice, function(){
projectModel.applicationUrlEth = applicationUrlEthCtrl.text
projectModel.saveProject()
verificationEthUrl.text = qsTr("waiting verifications")
worker.waitForTrReceipt(projectModel.registerContentHashTrHash, function(status, receipt)
{
worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost)
@ -262,7 +287,7 @@ Rectangle {
}
}
function registerUrl()
function registerUrl(gasPrice, callback)
{
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
{
@ -276,9 +301,10 @@ Rectangle {
inError.push(qsTr(applicationUrlHttpCtrl.text));
if (!worker.stopForInputError(inError))
{
registerToUrlHint(applicationUrlHttpCtrl.text, function(){
registerToUrlHint(applicationUrlHttpCtrl.text, gasPrice, function(){
projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text
projectModel.saveProject()
verificationUrl.text = qsTr("waiting verifications")
worker.waitForTrReceipt(projectModel.registerUrlTrHash, function(status, receipt)
{
worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost)
@ -286,6 +312,8 @@ Rectangle {
projectModel.registerUrlBlockNumber = bn
projectModel.saveProject()
root.updateVerification(bn, bn, trLost, verificationUrl)
root.registered()
callback()
});
})
})
@ -300,8 +328,12 @@ Rectangle {
width: 30
onClicked:
{
parent.registerHash(function(){
parent.registerUrl()
verificationEthUrl.text = ""
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
anchors.horizontalCenter: parent.horizontalCenter
Layout.preferredHeight: 60
Layout.preferredHeight: 75
spacing: 0
anchors.top: parent.top
anchors.topMargin: 10
@ -88,7 +88,7 @@ ColumnLayout
color: "#cccccc"
id: deleteImg
anchors.top: parent.top
anchors.topMargin: 6
anchors.topMargin: 7
visible: projectModel.stateListModel.count > 1
MouseArea
{

2
mix/qml/StatusPane.qml

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

3
mix/qml/WebPreview.qml

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

39
mix/qml/js/NetworkDeployment.js

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

1
mix/qml/js/TransactionHelper.js

@ -33,6 +33,7 @@ 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;
console.log(errorText);
if (error)
error(errorText);
}
else

46
test/libsolidity/SolidityWallet.cpp

@ -116,7 +116,7 @@ contract multiowned {
}
// 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;
uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return;
@ -128,7 +128,7 @@ contract multiowned {
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;
clearPending();
@ -142,7 +142,7 @@ contract multiowned {
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)];
if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return;
@ -154,7 +154,7 @@ contract multiowned {
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;
m_required = _newRequired;
clearPending();
@ -275,16 +275,17 @@ contract daylimit is multiowned {
// METHODS
// constructor - just records the present day's index.
function daylimit() {
// constructor - stores initial daily limit and records the present day's index.
function daylimit(uint _limit) {
m_dailyLimit = _limit;
m_lastDay = 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;
}
// (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;
}
@ -354,12 +355,14 @@ contract Wallet is multisig, multiowned, daylimit {
// METHODS
// constructor - just pass on the owner array to the multiowned.
function Wallet(address[] _owners, uint _required) multiowned(_owners, _required) {
// constructor - just pass on the owner array to the multiowned and
// the limit to daylimit
function Wallet(address[] _owners, uint _required, uint _daylimit)
multiowned(_owners, _required) daylimit(_daylimit) {
}
// 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);
}
@ -424,7 +427,12 @@ static unique_ptr<bytes> s_compiledWallet;
class WalletTestFramework: public ExecutionFramework
{
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)
{
@ -434,7 +442,7 @@ protected:
ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed");
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);
BOOST_REQUIRE(!m_output.empty());
}
@ -519,7 +527,7 @@ BOOST_AUTO_TEST_CASE(initial_owners)
u256("0x0000000000000000000000004c9113886af165b2de069d6e99430647e94a9fff"),
u256("0x0000000000000000000000003fb1cd2cd96c6d5c0b5eb3322d807b34482481d4")
};
deployWallet(0, owners, 4);
deployWallet(0, owners, 4, 2);
BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8)));
BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
for (u256 const& owner: owners)
@ -554,7 +562,9 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
BOOST_AUTO_TEST_CASE(daylimit)
{
deployWallet(200);
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(0)));
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(0x13)) == 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_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
BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save