diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 24afcb656..2515959ad 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -227,6 +227,7 @@
&Config
+
@@ -1798,6 +1799,11 @@ font-size: 14pt
Smart
+
+
+ &Sentinel...
+
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index c69e6e391..d7fc0b409 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -307,6 +307,14 @@ void Main::on_gasPrices_triggered()
}
}
+void Main::on_sentinel_triggered()
+{
+ bool ok;
+ QString sentinel = QInputDialog::getText(nullptr, "Enter sentinel address", "Enter the sentinel address for bad block reporting (e.g. http://badblockserver.com:8080). Enter nothing to disable.", QLineEdit::Normal, QString::fromStdString(ethereum()->sentinel()), &ok);
+ if (ok)
+ ethereum()->setSentinel(sentinel.toStdString());
+}
+
void Main::on_newIdentity_triggered()
{
KeyPair kp = KeyPair::create();
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 5ea1f5515..b1939534b 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -199,6 +199,7 @@ private slots:
// Config
void on_gasPrices_triggered();
+ void on_sentinel_triggered();
void refreshWhisper();
void refreshBlockChain();
diff --git a/eth/main.cpp b/eth/main.cpp
index c45dfe766..e60da08f5 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -115,6 +115,7 @@ void interactiveHelp()
<< " reprocess Reprocess a given block." << endl
<< " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl
<< " dumpreceipt Dumps a transation receipt." << endl
+ << " hashrate Print the current hashrate in hashes per second if the client is mining." << endl
<< " exit Exits the application." << endl;
}
@@ -193,7 +194,7 @@ void help()
<< "General Options:" << endl
<< " -d,--db-path Load database from path (default: " << getDataDir() << ")" << endl
#if ETH_EVMJIT || !ETH_TRUE
- << " --vm= Select VM. Options are: jit, smart. (default: interpreter)" << endl
+ << " -J,--jit Enable EVM JIT (default: off)." << endl
#endif
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
@@ -284,1567 +285,1463 @@ void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
this_thread::sleep_for(chrono::milliseconds(100));
}
-int main(int argc, char** argv)
+void interactiveMode(eth::Client* c, std::shared_ptr gasPricer, WebThreeDirect& web3, KeyManager& keyManager, string& logbuf, string& additional, function getPassword, function getAccountPassword, NetworkPreferences netPrefs, Address beneficiary, Address signingKey, TransactionPriority priority)
{
- // Init defaults
- Defaults::get();
-
- /// Operating mode.
- OperationMode mode = OperationMode::Node;
- string dbPath;
- unsigned prime = 0;
- bool yesIReallyKnowWhatImDoing = false;
-
- /// File name for import/export.
- string filename;
- bool safeImport = false;
-
- /// Hashes/numbers for export range.
- string exportFrom = "1";
- string exportTo = "latest";
- Format exportFormat = Format::Binary;
-
- /// General params for Node operation
- NodeMode nodeMode = NodeMode::Full;
- bool interactive = false;
-#if ETH_JSONRPC
- int jsonrpc = -1;
-#endif
- string jsonAdmin;
- bool upnp = true;
- WithExisting killChain = WithExisting::Trust;
- string sentinel;
-
- /// Networking params.
- string clientName;
- string listenIP;
- unsigned short listenPort = 30303;
- string publicIP;
- string remoteHost;
- unsigned short remotePort = 30303;
- unsigned peers = 11;
- bool bootstrap = false;
- bool disableDiscovery = false;
- bool pinning = false;
- unsigned networkId = 0;
-
- /// Mining params
- unsigned mining = 0;
- bool forceMining = false;
- bool mineOnWrongChain = false;
- Address signingKey;
- Address sessionKey;
- Address beneficiary = signingKey;
-
- /// Structured logging params
- bool structuredLogging = false;
- string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
- string structuredLoggingURL;
-
- /// Transaction params
- TransactionPriority priority = TransactionPriority::Medium;
-// double etherPrice = 30.679;
-// double blockFees = 15.0;
- u256 askPrice("500000000000");
- u256 bidPrice("500000000000");
-
- // javascript console
- bool useConsole = false;
-
- /// Wallet password stuff
- string masterPassword;
-
- string configFile = getDataDir() + "/config.rlp";
- bytes b = contents(configFile);
-
- strings passwordsToNote;
- Secrets toImport;
- if (b.size())
+ additional = "Press Enter";
+ string l;
+ while (!g_exit)
{
- RLP config(b);
- if (config[0].size() == 32) // secret key - import and forget.
+ g_silence = false;
+ cout << logbuf << "Press Enter" << flush;
+ std::getline(cin, l);
+ logbuf.clear();
+ g_silence = true;
+
+#if ETH_READLINE
+ if (l.size())
+ add_history(l.c_str());
+ if (auto c = readline("> "))
{
- Secret s = config[0].toHash();
- toImport.push_back(s);
+ l = c;
+ free(c);
}
- else // new format - just use it as an address.
- signingKey = config[0].toHash();
- beneficiary = config[1].toHash();
- }
-
- MinerCLI m(MinerCLI::OperationMode::None);
-
- for (int i = 1; i < argc; ++i)
- {
- string arg = argv[i];
- if (m.interpretOption(i, argc, argv)) {}
- else if (arg == "--listen-ip" && i + 1 < argc)
- listenIP = argv[++i];
- else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
+ else
+ break;
+#else
+ string l;
+ cout << "> " << flush;
+ std::getline(cin, l);
+#endif
+ istringstream iss(l);
+ string cmd;
+ iss >> cmd;
+ boost::to_lower(cmd);
+ if (cmd == "netstart")
{
- if (arg == "-l")
- cerr << "-l is DEPRECATED. It will be removed for the Frontier. Use --listen-port instead." << endl;
- listenPort = (short)atoi(argv[++i]);
+ iss >> netPrefs.listenPort;
+ web3.setNetworkPreferences(netPrefs);
+ web3.startNetwork();
}
- else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
+ else if (cmd == "connect")
{
- if (arg == "-u")
- cerr << "-u is DEPRECATED. It will be removed for the Frontier. Use --public-ip instead." << endl;
- publicIP = argv[++i];
+ string addrPort;
+ iss >> addrPort;
+ web3.addNode(p2p::NodeId(), addrPort);
}
- else if ((arg == "-r" || arg == "--remote") && i + 1 < argc)
- remoteHost = argv[++i];
- else if ((arg == "-p" || arg == "--port") && i + 1 < argc)
+ else if (cmd == "netstop")
+ web3.stopNetwork();
+ else if (c && cmd == "minestart")
+ c->startMining();
+ else if (c && cmd == "minestop")
+ c->stopMining();
+ else if (c && cmd == "mineforce")
{
- if (arg == "-p")
- cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
- remotePort = (short)atoi(argv[++i]);
+ string enable;
+ iss >> enable;
+ c->setForceMining(isTrue(enable));
}
- else if (arg == "--password" && i + 1 < argc)
- passwordsToNote.push_back(argv[++i]);
- else if (arg == "--master" && i + 1 < argc)
- masterPassword = argv[++i];
- else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
+ else if (cmd == "verbosity")
{
- mode = OperationMode::Import;
- filename = argv[++i];
+ if (iss.peek() != -1)
+ iss >> g_logVerbosity;
+ cout << "Verbosity: " << g_logVerbosity << endl;
}
- else if (arg == "--dont-check")
- safeImport = true;
- else if ((arg == "-E" || arg == "--export") && i + 1 < argc)
+ else if (cmd == "address")
{
- mode = OperationMode::Export;
- filename = argv[++i];
+ cout << "Current mining beneficiary:" << endl << beneficiary << endl;
+ cout << "Current signing account:" << endl << signingKey << endl;
}
- else if (arg == "--prime" && i + 1 < argc)
- try
- {
- prime = stoi(argv[++i]);
- }
- catch (...)
- {
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
- }
- else if (arg == "--yes-i-really-know-what-im-doing")
- yesIReallyKnowWhatImDoing = true;
- else if (arg == "--sentinel" && i + 1 < argc)
- sentinel = argv[++i];
- else if (arg == "--mine-on-wrong-chain")
- mineOnWrongChain = true;
- else if (arg == "--format" && i + 1 < argc)
+ else if (c && cmd == "blockhashfromnumber")
{
- string m = argv[++i];
- if (m == "binary")
- exportFormat = Format::Binary;
- else if (m == "hex")
- exportFormat = Format::Hex;
- else if (m == "human")
- exportFormat = Format::Human;
- else
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << m << endl;
- return -1;
+ unsigned number;
+ iss >> number;
+ cout << " hash of block: " << c->hashFromNumber(number).hex() << endl;
}
}
- else if (arg == "--to" && i + 1 < argc)
- exportTo = argv[++i];
- else if (arg == "--from" && i + 1 < argc)
- exportFrom = argv[++i];
- else if (arg == "--only" && i + 1 < argc)
- exportTo = exportFrom = argv[++i];
- else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc)
+ else if (c && cmd == "numberfromblockhash")
{
- if (arg == "-n")
- cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use --upnp instead." << endl;
- string m = argv[++i];
- if (isTrue(m))
- upnp = true;
- else if (isFalse(m))
- upnp = false;
- else
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << m << endl;
- return -1;
+ string stringHash;
+ iss >> stringHash;
+
+ h256 hash = h256(fromHex(stringHash));
+ cout << " number of block: " << c->numberFromHash(hash) << endl;
}
}
- else if (arg == "--network-id" && i + 1 < argc)
- try {
- networkId = stol(argv[++i]);
- }
- catch (...)
- {
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
- }
- else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
- killChain = WithExisting::Kill;
- else if (arg == "-R" || arg == "--rebuild")
- killChain = WithExisting::Verify;
- else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
+ else if (c && cmd == "block")
+ cout << "Current block: " << c->blockChain().details().number << endl;
+ else if (c && cmd == "blockqueue")
+ cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl;
+ else if (c && cmd == "hashrate")
+ cout << "Current hash rate: " << toString(c->hashrate()) << " hashes per second." << endl;
+ else if (c && cmd == "findblock")
{
- if (arg == "-c")
- cerr << "-c is DEPRECATED. It will be removed for the Frontier. Use --client-name instead." << endl;
- clientName = argv[++i];
- }
- else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
- try {
- beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
- }
- catch (BadHexCharacter&)
- {
- cerr << "Bad hex in " << arg << " option: " << argv[i] << endl;
- return -1;
- }
- catch (...)
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ string stringHash;
+ iss >> stringHash;
+
+ h256 hash = h256(fromHex(stringHash));
+
+ // search in blockchain
+ cout << "search in blockchain... " << endl;
+ try
+ {
+ cout << c->blockInfo(hash) << endl;
+ }
+ catch(Exception& _e)
+ {
+ cout << "block not in blockchain" << endl;
+ cout << boost::diagnostic_information(_e) << endl;
+ }
+
+ cout << "search in blockqueue... " << endl;
+
+ switch(c->blockQueue().blockStatus(hash))
+ {
+ case QueueStatus::Ready:
+ cout << "Ready" << endl;
+ break;
+ case QueueStatus::Importing:
+ cout << "Importing" << endl;
+ break;
+ case QueueStatus::UnknownParent:
+ cout << "UnknownParent" << endl;
+ break;
+ case QueueStatus::Bad:
+ cout << "Bad" << endl;
+ break;
+ case QueueStatus::Unknown:
+ cout << "Unknown" << endl;
+ break;
+ default:
+ cout << "invalid queueStatus" << endl;
+ }
}
- else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
- {
- Secret s(fromHex(argv[++i]));
- toImport.push_back(s);
- signingKey = toAddress(s);
- }
- else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
- {
- Secret s(fromHex(argv[++i]));
- toImport.push_back(s);
- sessionKey = toAddress(s);
+ else
+ cwarn << "Require parameter: findblock HASH";
}
- else if ((arg == "--sign-key") && i + 1 < argc)
- sessionKey = Address(fromHex(argv[++i]));
- else if ((arg == "--session-sign-key") && i + 1 < argc)
- sessionKey = Address(fromHex(argv[++i]));
- else if (arg == "--structured-logging-format" && i + 1 < argc)
- structuredLoggingFormat = string(argv[++i]);
- else if (arg == "--structured-logging")
- structuredLogging = true;
- else if (arg == "--structured-logging-url" && i + 1 < argc)
+ else if (c && cmd == "firstunknown")
+ cout << "first unknown blockhash: " << c->blockQueue().firstUnknown().hex() << endl;
+ else if (c && cmd == "retryunknown")
+ c->retryUnknown();
+ else if (cmd == "peers")
{
- structuredLogging = true;
- structuredLoggingURL = argv[++i];
+ for (auto it: web3.peers())
+ cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
+ << std::chrono::duration_cast(it.lastPing).count() << "ms"
+ << endl;
}
- 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 (cmd == "newaccount")
{
- try
- {
- CanonBlockChain::setGenesisNonce(Nonce(argv[++i]));
+ string name;
+ std::getline(iss, name);
+ auto s = Secret::random();
+ string password;
+ while (password.empty())
+ {
+ password = getPassword("Please enter a password to protect this key (press enter for protection only be the MASTER password/keystore): ");
+ string confirm = getPassword("Please confirm the password by entering it again: ");
+ if (password != confirm)
+ {
+ cout << "Passwords were different. Try again." << endl;
+ password.clear();
+ }
}
- catch (...)
+ if (!password.empty())
{
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ cout << "Enter a hint for this password: " << flush;
+ string hint;
+ std::getline(cin, hint);
+ keyManager.import(s, name, password, hint);
}
+ else
+ keyManager.import(s, name);
+ cout << "New account created: " << toAddress(s);
}
-/* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
+ else if (c && cmd == "accounts")
{
- try
+ cout << "Accounts:" << endl;
+ u256 total = 0;
+ for (auto const& address: keyManager.accounts())
{
- blockFees = stof(argv[++i]);
+ auto b = c->balanceAt(address);
+ cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl;
+ total += b;
}
- catch (...)
- {
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
+ }
+ else if (c && cmd == "transact")
+ {
+ auto const& bc =c->blockChain();
+ auto h = bc.currentHash();
+ auto blockData = bc.block(h);
+ BlockInfo info(blockData);
+ if (iss.peek() != -1)
+ {
+ string hexAddr;
+ u256 amount;
+ u256 gasPrice;
+ u256 gas;
+ string sechex;
+ string sdata;
+
+ iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
+
+ if (!gasPrice)
+ gasPrice = gasPricer->bid(priority);
+
+ cnote << "Data:";
+ cnote << sdata;
+ bytes data = dev::eth::parseData(sdata);
+ cnote << "Bytes:";
+ string sbd = asString(data);
+ bytes bbd = asBytes(sbd);
+ stringstream ssbd;
+ ssbd << bbd;
+ cnote << ssbd.str();
+ int ssize = sechex.length();
+ int size = hexAddr.length();
+ u256 minGas = (u256)Transaction::gasRequired(data, 0);
+ if (size < 40)
+ {
+ if (size > 0)
+ cwarn << "Invalid address length:" << size;
+ }
+ else if (gas < minGas)
+ cwarn << "Minimum gas amount is" << minGas;
+ else if (ssize < 40)
+ {
+ if (ssize > 0)
+ cwarn << "Invalid secret length:" << ssize;
+ }
+ else
+ {
+ try
+ {
+ Secret secret = h256(fromHex(sechex));
+ Address dest = h160(fromHex(hexAddr));
+ c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, transaction rejected";
+ cwarn << boost::diagnostic_information(_e);
+ }
+ catch (...)
+ {
+ cwarn << "transaction rejected";
+ }
+ }
}
+ else
+ cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
- else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
+
+ else if (c && cmd == "transactnonce")
{
- try
+ auto const& bc =c->blockChain();
+ auto h = bc.currentHash();
+ auto blockData = bc.block(h);
+ BlockInfo info(blockData);
+ if (iss.peek() != -1)
+ {
+ string hexAddr;
+ u256 amount;
+ u256 gasPrice;
+ u256 gas;
+ string sechex;
+ string sdata;
+ u256 nonce;
+
+ iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata >> nonce;
+
+ if (!gasPrice)
+ gasPrice = gasPricer->bid(priority);
+
+ cnote << "Data:";
+ cnote << sdata;
+ bytes data = dev::eth::parseData(sdata);
+ cnote << "Bytes:";
+ string sbd = asString(data);
+ bytes bbd = asBytes(sbd);
+ stringstream ssbd;
+ ssbd << bbd;
+ cnote << ssbd.str();
+ int ssize = sechex.length();
+ int size = hexAddr.length();
+ u256 minGas = (u256)Transaction::gasRequired(data, 0);
+ if (size < 40)
+ {
+ if (size > 0)
+ cwarn << "Invalid address length:" << size;
+ }
+ else if (gas < minGas)
+ cwarn << "Minimum gas amount is" << minGas;
+ else if (ssize < 40)
+ {
+ if (ssize > 0)
+ cwarn << "Invalid secret length:" << ssize;
+ }
+ else
+ {
+ try
+ {
+ Secret secret = h256(fromHex(sechex));
+ Address dest = h160(fromHex(hexAddr));
+ c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce);
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, transaction rejected";
+ cwarn << boost::diagnostic_information(_e);
+ }
+ catch (...)
+ {
+ cwarn << "transaction rejected";
+ }
+ }
+ }
+ else
+ cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA NONCE";
+ }
+
+ else if (c && cmd == "txcreate")
+ {
+ auto const& bc =c->blockChain();
+ auto h = bc.currentHash();
+ auto blockData = bc.block(h);
+ BlockInfo info(blockData);
+ if (iss.peek() != -1)
+ {
+ u256 amount;
+ u256 gasPrice;
+ u256 gas;
+ string sechex;
+ string sdata;
+
+ iss >> amount >> gasPrice >> gas >> sechex >> sdata;
+
+ if (!gasPrice)
+ gasPrice = gasPricer->bid(priority);
+
+ cnote << "Data:";
+ cnote << sdata;
+ bytes data = dev::eth::parseData(sdata);
+ cnote << "Bytes:";
+ string sbd = asString(data);
+ bytes bbd = asBytes(sbd);
+ stringstream ssbd;
+ ssbd << bbd;
+ cnote << ssbd.str();
+ int ssize = sechex.length();
+ u256 minGas = (u256)Transaction::gasRequired(data, 0);
+ if (gas < minGas)
+ cwarn << "Minimum gas amount is" << minGas;
+ else if (ssize < 40)
+ {
+ if (ssize > 0)
+ cwarn << "Invalid secret length:" << ssize;
+ }
+ else
+ {
+ try
+ {
+ Secret secret = h256(fromHex(sechex));
+ cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, transaction rejected";
+ cwarn << boost::diagnostic_information(_e);
+ }
+ catch (...)
+ {
+ cwarn << "transaction rejected";
+ }
+ }
+ }
+ else
+ cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT";
+ }
+#if ETH_FATDB
+ else if (c && cmd == "listcontracts")
+ {
+ auto acs =c->addresses();
+ string ss;
+ for (auto const& i: acs)
+ if ( c->codeAt(i, PendingBlock).size())
+ {
+ ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
+ cout << ss << endl;
+ }
+ }
+ else if (c && cmd == "listaccounts")
+ {
+ auto acs =c->addresses();
+ string ss;
+ for (auto const& i: acs)
+ if ( c->codeAt(i, PendingBlock).empty())
+ {
+ ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
+ cout << ss << endl;
+ }
+ }
+ else if (c && cmd == "balanceat")
+ {
+ if (iss.peek() != -1)
{
- etherPrice = stof(argv[++i]);
+ string stringHash;
+ iss >> stringHash;
+
+ Address address = h160(fromHex(stringHash));
+
+ cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl;
}
- catch (...)
+ }
+ else if (c && cmd == "balanceatblock")
+ {
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ string stringHash;
+ unsigned blocknumber;
+ iss >> stringHash >> blocknumber;
+
+ Address address = h160(fromHex(stringHash));
+
+ cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address, blocknumber)) << endl;
}
- }*/
- else if (arg == "--ask" && i + 1 < argc)
+ }
+ else if (c && cmd == "storageat")
{
- try
+ if (iss.peek() != -1)
{
- askPrice = u256(argv[++i]);
+ string stringHash;
+ iss >> stringHash;
+
+ Address address = h160(fromHex(stringHash));
+
+ cout << "storage at " << stringHash << " is: " << endl;
+ for (auto s: c->storageAt(address))
+ cout << toHex(s.first) << " : " << toHex(s.second) << endl;
}
- catch (...)
+ }
+ else if (c && cmd == "storageatblock")
+ {
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ string stringHash;
+ unsigned blocknumber;
+ iss >> stringHash >> blocknumber;
+
+ Address address = h160(fromHex(stringHash));
+
+ cout << "storage at " << stringHash << " is: " << endl;
+ for (auto s: c->storageAt(address, blocknumber))
+ cout << "\"0x" << toHex(s.first) << "\" : \"0x" << toHex(s.second) << "\"," << endl;
}
}
- else if (arg == "--bid" && i + 1 < argc)
+ else if (c && cmd == "codeat")
{
- try
+ if (iss.peek() != -1)
{
- bidPrice = u256(argv[++i]);
+ string stringHash;
+ iss >> stringHash;
+
+ Address address = h160(fromHex(stringHash));
+
+ cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl;
}
- catch (...)
+ }
+#endif
+
+ else if (c && cmd == "send")
+ {
+ if (iss.peek() != -1)
{
- cerr << "Bad " << arg << " option: " << argv[i] << endl;
- return -1;
+ string hexAddr;
+ u256 amount;
+
+ iss >> hexAddr >> amount;
+ int size = hexAddr.length();
+ if (size < 40)
+ {
+ if (size > 0)
+ cwarn << "Invalid address length:" << size;
+ }
+ else
+ {
+ auto const& bc =c->blockChain();
+ auto h = bc.currentHash();
+ auto blockData = bc.block(h);
+ BlockInfo info(blockData);
+ u256 minGas = (u256)Transaction::gasRequired(bytes(), 0);
+ try
+ {
+ Address dest = h160(fromHex(hexAddr, WhenError::Throw));
+ c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), amount, dest, bytes(), minGas);
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, transaction rejected";
+ cwarn << boost::diagnostic_information(_e);
+ }
+ catch (...)
+ {
+ cwarn << "transaction rejected";
+ }
+ }
}
+ else
+ cwarn << "Require parameters: send ADDRESS AMOUNT";
}
- else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
+ else if (c && cmd == "contract")
{
- string m = boost::to_lower_copy(string(argv[++i]));
- if (m == "lowest")
- priority = TransactionPriority::Lowest;
- else if (m == "low")
- priority = TransactionPriority::Low;
- else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
- priority = TransactionPriority::Medium;
- else if (m == "high")
- priority = TransactionPriority::High;
- else if (m == "highest")
- priority = TransactionPriority::Highest;
+ auto const& bc =c->blockChain();
+ auto h = bc.currentHash();
+ auto blockData = bc.block(h);
+ BlockInfo info(blockData);
+ if (iss.peek() != -1)
+ {
+ u256 endowment;
+ u256 gas;
+ u256 gasPrice;
+ string sinit;
+ iss >> endowment >> gasPrice >> gas >> sinit;
+ trim_all(sinit);
+ int size = sinit.length();
+ bytes init;
+ cnote << "Init:";
+ cnote << sinit;
+ cnote << "Code size:" << size;
+ if (size < 1)
+ cwarn << "No code submitted";
+ else
+ {
+ cnote << "Assembled:";
+ stringstream ssc;
+ try
+ {
+ init = fromHex(sinit, WhenError::Throw);
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, code rejected";
+ cwarn << boost::diagnostic_information(_e);
+ init = bytes();
+ }
+ catch (...)
+ {
+ cwarn << "code rejected";
+ init = bytes();
+ }
+ ssc.str(string());
+ ssc << disassemble(init);
+ cnote << "Init:";
+ cnote << ssc.str();
+ }
+ u256 minGas = (u256)Transaction::gasRequired(init, 0);
+ if (!init.size())
+ cwarn << "Contract creation aborted, no init code.";
+ else if (endowment < 0)
+ cwarn << "Invalid endowment";
+ else if (gas < minGas)
+ cwarn << "Minimum gas amount is" << minGas;
+ else
+ c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), endowment, init, gas, gasPrice);
+ }
else
- try {
- priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
+ cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
+ }
+ else if (c && cmd == "dumpreceipt")
+ {
+ unsigned block;
+ unsigned index;
+ iss >> block >> index;
+ dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
+ auto rb = r.rlp();
+ cout << "RLP: " << RLP(rb) << endl;
+ cout << "Hex: " << toHex(rb) << endl;
+ cout << r << endl;
+ }
+ else if (c && cmd == "reprocess")
+ {
+ string block;
+ iss >> block;
+ h256 blockHash;
+ try
+ {
+ if (block.size() == 64 || block.size() == 66)
+ blockHash = h256(block);
+ else
+ blockHash = c->blockChain().numberHash(stoi(block));
+ c->state(blockHash);
+ }
+ catch (...)
+ {}
+ }
+ else if (c && cmd == "dumptrace")
+ {
+ unsigned block;
+ unsigned index;
+ string filename;
+ string format;
+ iss >> block >> index >> filename >> format;
+ ofstream f;
+ f.open(filename);
+
+ dev::eth::State state = c->state(index + 1,c->blockChain().numberHash(block));
+ if (index < state.pending().size())
+ {
+ Executive e(state, c->blockChain(), 0);
+ Transaction t = state.pending()[index];
+ state = state.fromPending(index);
+ try
+ {
+ OnOpFunc oof;
+ if (format == "pretty")
+ oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
+ {
+ dev::eth::VM* vm = vvm;
+ dev::eth::ExtVM const* ext = static_cast(vextVM);
+ f << endl << " STACK" << endl;
+ for (auto i: vm->stack())
+ f << (h256)i << endl;
+ f << " MEMORY" << endl << dev::memDump(vm->memory());
+ f << " STORAGE" << endl;
+ for (auto const& i: ext->state().storage(ext->myAddress))
+ f << showbase << hex << i.first << ": " << i.second << endl;
+ f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << gas << " | -" << dec << gasCost << " | " << newMemSize << "x32";
+ };
+ else if (format == "standard")
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
+ {
+ dev::eth::VM* vm = vvm;
+ dev::eth::ExtVM const* ext = static_cast(vextVM);
+ f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
+ };
+ else if (format == "standard+")
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
+ {
+ dev::eth::VM* vm = vvm;
+ dev::eth::ExtVM const* ext = static_cast(vextVM);
+ if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
+ for (auto const& i: ext->state().storage(ext->myAddress))
+ f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
+ f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
+ };
+ e.initialize(t);
+ if (!e.execute())
+ e.go(oof);
+ e.finalize();
}
- catch (...) {
- cerr << "Unknown " << arg << " option: " << m << endl;
- return -1;
+ catch(Exception const& _e)
+ {
+ // TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain.
+ cwarn << diagnostic_information(_e);
}
+ }
}
- else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
+ else if (c && cmd == "inspect")
{
- string m = argv[++i];
- if (isTrue(m))
- mining = ~(unsigned)0;
- else if (isFalse(m))
- mining = 0;
+ string rechex;
+ iss >> rechex;
+
+ if (rechex.length() != 40)
+ cwarn << "Invalid address length";
else
- try {
- mining = stoi(m);
+ {
+ auto h = h160(fromHex(rechex));
+ stringstream s;
+
+ try
+ {
+ auto storage =c->storageAt(h, PendingBlock);
+ for (auto const& i: storage)
+ s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
+ s << endl << disassemble( c->codeAt(h, PendingBlock)) << endl;
+
+ string outFile = getDataDir() + "/" + rechex + ".evm";
+ ofstream ofs;
+ ofs.open(outFile, ofstream::binary);
+ ofs.write(s.str().c_str(), s.str().length());
+ ofs.close();
+
+ cnote << "Saved" << rechex << "to" << outFile;
}
- catch (...) {
- cerr << "Unknown " << arg << " option: " << m << endl;
- return -1;
+ catch (dev::InvalidTrie)
+ {
+ cwarn << "Corrupted trie.";
}
+ }
}
- else if (arg == "-b" || arg == "--bootstrap")
- bootstrap = true;
- else if (arg == "--no-discovery")
- disableDiscovery = true;
- else if (arg == "--pin")
- pinning = true;
- else if (arg == "-f" || arg == "--force-mining")
- forceMining = true;
- else if (arg == "-i" || arg == "--interactive")
- interactive = true;
-#if ETH_JSONRPC
- else if ((arg == "-j" || arg == "--json-rpc"))
- jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
- else if (arg == "--json-rpc-port" && i + 1 < argc)
- jsonrpc = atoi(argv[++i]);
- else if (arg == "--json-admin" && i + 1 < argc)
- jsonAdmin = argv[++i];
-#endif
-#if ETH_JSCONSOLE
- else if (arg == "--console")
- useConsole = true;
-#endif
- else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
- g_logVerbosity = atoi(argv[++i]);
- else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
- peers = atoi(argv[++i]);
- else if ((arg == "-o" || arg == "--mode") && i + 1 < argc)
+ else if (cmd == "setsigningkey")
{
- string m = argv[++i];
- if (m == "full")
- nodeMode = NodeMode::Full;
- else if (m == "peer")
- nodeMode = NodeMode::PeerServer;
+ if (iss.peek() != -1)
+ {
+ string hexSec;
+ iss >> hexSec;
+ signingKey = Address(fromHex(hexSec));
+ }
else
+ cwarn << "Require parameter: setSecret HEXSECRETKEY";
+ }
+ else if (cmd == "setaddress")
+ {
+ if (iss.peek() != -1)
{
- cerr << "Unknown mode: " << m << endl;
- return -1;
+ string hexAddr;
+ iss >> hexAddr;
+ if (hexAddr.length() != 40)
+ cwarn << "Invalid address length: " << hexAddr.length();
+ else
+ {
+ try
+ {
+ beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
+ }
+ catch (BadHexCharacter& _e)
+ {
+ cwarn << "invalid hex character, coinbase rejected";
+ cwarn << boost::diagnostic_information(_e);
+ }
+ catch (...)
+ {
+ cwarn << "coinbase rejected";
+ }
+ }
}
+ else
+ cwarn << "Require parameter: setAddress HEXADDRESS";
}
-#if ETH_EVMJIT
- else if (arg == "--vm=jit")
- VMFactory::setKind(VMKind::JIT);
- else if (arg == "--vm=smart")
- VMFactory::setKind(VMKind::Smart);
-#endif
- else if (arg == "-h" || arg == "--help")
- help();
- else if (arg == "-V" || arg == "--version")
- version();
- else
+ else if (cmd == "exportconfig")
{
- cerr << "Invalid argument: " << arg << endl;
- exit(-1);
+ if (iss.peek() != -1)
+ {
+ string path;
+ iss >> path;
+ RLPStream config(2);
+ config << signingKey << beneficiary;
+ writeFile(path, config.out());
+ }
+ else
+ cwarn << "Require parameter: exportConfig PATH";
+ }
+ else if (cmd == "importconfig")
+ {
+ if (iss.peek() != -1)
+ {
+ string path;
+ iss >> path;
+ bytes b = contents(path);
+ if (b.size())
+ {
+ RLP config(b);
+ signingKey = config[0].toHash();
+ beneficiary = config[1].toHash();
+ }
+ else
+ cwarn << path << "has no content!";
+ }
+ else
+ cwarn << "Require parameter: importConfig PATH";
}
+ else if (cmd == "help")
+ interactiveHelp();
+ else if (cmd == "exit")
+ break;
+ else
+ cout << "Unrecognised command. Type 'help' for help in interactive mode." << endl;
}
+}
- m.execute();
+int main(int argc, char** argv)
+{
+ // Init defaults
+ Defaults::get();
- KeyManager keyManager;
- for (auto const& s: passwordsToNote)
- keyManager.notePassword(s);
+ /// Operating mode.
+ OperationMode mode = OperationMode::Node;
+ string dbPath;
+ unsigned prime = 0;
+ bool yesIReallyKnowWhatImDoing = false;
- {
- RLPStream config(2);
- config << signingKey << beneficiary;
- writeFile(configFile, config.out());
- }
+ /// File name for import/export.
+ string filename;
+ bool safeImport = false;
- if (sessionKey)
- signingKey = sessionKey;
+ /// Hashes/numbers for export range.
+ string exportFrom = "1";
+ string exportTo = "latest";
+ Format exportFormat = Format::Binary;
- if (!clientName.empty())
- clientName += "/";
+ /// General params for Node operation
+ NodeMode nodeMode = NodeMode::Full;
+ bool interactive = false;
+#if ETH_JSONRPC
+ int jsonrpc = -1;
+#endif
+ string jsonAdmin;
+ bool upnp = true;
+ WithExisting killChain = WithExisting::Trust;
+ bool jit = false;
+ string sentinel;
- string logbuf;
- std::string additional;
- if (interactive)
- g_logPost = [&](std::string const& a, char const*){
- static SpinLock s_lock;
- SpinGuard l(s_lock);
+ /// Networking params.
+ string clientName;
+ string listenIP;
+ unsigned short listenPort = 30303;
+ string publicIP;
+ string remoteHost;
+ unsigned short remotePort = 30303;
+ unsigned peers = 11;
+ bool bootstrap = false;
+ bool disableDiscovery = false;
+ bool pinning = false;
+ unsigned networkId = 0;
- if (g_silence)
- logbuf += a + "\n";
- else
- cout << "\r \r" << a << endl << additional << flush;
+ /// Mining params
+ unsigned mining = 0;
+ bool forceMining = false;
+ bool mineOnWrongChain = false;
+ Address signingKey;
+ Address sessionKey;
+ Address beneficiary = signingKey;
- // helpful to use OutputDebugString on windows
- #ifdef _WIN32
- {
- OutputDebugStringA(a.data());
- OutputDebugStringA("\n");
- }
- #endif
- };
+ /// Structured logging params
+ bool structuredLogging = false;
+ string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
+ string structuredLoggingURL;
- auto getPassword = [&](string const& prompt){
- auto s = g_silence;
- g_silence = true;
- cout << endl;
- string ret = dev::getPassword(prompt);
- g_silence = s;
- return ret;
- };
- auto getAccountPassword = [&](Address const& a){
- return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): ");
- };
+ /// Transaction params
+ TransactionPriority priority = TransactionPriority::Medium;
+// double etherPrice = 30.679;
+// double blockFees = 15.0;
+ u256 askPrice("500000000000");
+ u256 bidPrice("500000000000");
- 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;
- auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
- dev::WebThreeDirect web3(
- WebThreeDirect::composeClientVersion("++eth", clientName),
- dbPath,
- killChain,
- nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(),
- netPrefs,
- &nodesState);
- web3.ethereum()->setMineOnBadChain(mineOnWrongChain);
- web3.ethereum()->setSentinel(sentinel);
+ // javascript console
+ bool useConsole = false;
- auto toNumber = [&](string const& s) -> unsigned {
- if (s == "latest")
- return web3.ethereum()->number();
- if (s.size() == 64 || (s.size() == 66 && s.substr(0, 2) == "0x"))
- return web3.ethereum()->blockChain().number(h256(s));
- try {
- return stol(s);
- }
- catch (...)
- {
- cerr << "Bad block number/hash option: " << s << endl;
- exit(-1);
- }
- };
+ /// Wallet password stuff
+ string masterPassword;
- if (mode == OperationMode::Export)
- {
- ofstream fout(filename, std::ofstream::binary);
- ostream& out = (filename.empty() || filename == "--") ? cout : fout;
+ string configFile = getDataDir() + "/config.rlp";
+ bytes b = contents(configFile);
- unsigned last = toNumber(exportTo);
- for (unsigned i = toNumber(exportFrom); i <= last; ++i)
+ strings passwordsToNote;
+ Secrets toImport;
+ if (b.size())
+ {
+ RLP config(b);
+ if (config[0].size() == 32) // secret key - import and forget.
{
- bytes block = web3.ethereum()->blockChain().block(web3.ethereum()->blockChain().numberHash(i));
- switch (exportFormat)
- {
- case Format::Binary: out.write((char const*)block.data(), block.size()); break;
- case Format::Hex: out << toHex(block) << endl; break;
- case Format::Human: out << RLP(block) << endl; break;
- default:;
- }
+ Secret s = config[0].toHash();
+ toImport.push_back(s);
}
- return 0;
+ else // new format - just use it as an address.
+ signingKey = config[0].toHash();
+ beneficiary = config[1].toHash();
}
- if (mode == OperationMode::Import)
+ MinerCLI m(MinerCLI::OperationMode::None);
+
+ for (int i = 1; i < argc; ++i)
{
- ifstream fin(filename, std::ifstream::binary);
- istream& in = (filename.empty() || filename == "--") ? cin : fin;
- unsigned alreadyHave = 0;
- unsigned good = 0;
- unsigned futureTime = 0;
- unsigned unknownParent = 0;
- unsigned bad = 0;
- chrono::steady_clock::time_point t = chrono::steady_clock::now();
- double last = 0;
- unsigned lastImported = 0;
- unsigned imported = 0;
- while (in.peek() != -1)
+ string arg = argv[i];
+ if (m.interpretOption(i, argc, argv)) {}
+ else if (arg == "--listen-ip" && i + 1 < argc)
+ listenIP = argv[++i];
+ else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
{
- bytes block(8);
- in.read((char*)block.data(), 8);
- block.resize(RLP(block, RLP::LaisezFaire).actualSize());
- in.read((char*)block.data() + 8, block.size() - 8);
-
- switch (web3.ethereum()->queueBlock(block, safeImport))
- {
- case ImportResult::Success: good++; break;
- case ImportResult::AlreadyKnown: alreadyHave++; break;
- case ImportResult::UnknownParent: unknownParent++; break;
- case ImportResult::FutureTimeUnknown: unknownParent++; futureTime++; break;
- case ImportResult::FutureTimeKnown: futureTime++; break;
- default: bad++; break;
- }
-
- // sync chain with queue
- tuple r = web3.ethereum()->syncQueue(10);
- imported += get<2>(r);
-
- double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0;
- if ((unsigned)e >= last + 10)
- {
- auto i = imported - lastImported;
- auto d = e - last;
- cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
- last = (unsigned)e;
- lastImported = imported;
-// cout << web3.ethereum()->blockQueueStatus() << endl;
- }
+ if (arg == "-l")
+ cerr << "-l is DEPRECATED. It will be removed for the Frontier. Use --listen-port instead." << endl;
+ listenPort = (short)atoi(argv[++i]);
}
-
- while (web3.ethereum()->blockQueue().items().first + web3.ethereum()->blockQueue().items().second > 0)
+ else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
{
- this_thread::sleep_for(chrono::seconds(1));
- web3.ethereum()->syncQueue(100000);
+ if (arg == "-u")
+ cerr << "-u is DEPRECATED. It will be removed for the Frontier. Use --public-ip instead." << endl;
+ publicIP = argv[++i];
}
- double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0;
- 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");
- unordered_set primes = RLP(pd).toUnorderedSet();
- while (true)
+ else if ((arg == "-r" || arg == "--remote") && i + 1 < argc)
+ remoteHost = argv[++i];
+ else if ((arg == "-p" || arg == "--port") && i + 1 < argc)
{
- if (!prime)
- try
- {
- prime = stoi(getPassword("To enter the Frontier, enter a 6 digit prime that you have not entered before: "));
- }
- catch (...) {}
- if (isPrime(prime) && !primes.count(prime))
- break;
- prime = 0;
+ if (arg == "-p")
+ cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
+ remotePort = (short)atoi(argv[++i]);
}
- primes.insert(prime);
- writeFile(getDataDir() + "primes", rlp(primes));
- }
-
- if (keyManager.exists())
- {
- if (masterPassword.empty() || !keyManager.load(masterPassword))
- while (true)
- {
- masterPassword = getPassword("Please enter your MASTER password: ");
- if (keyManager.load(masterPassword))
- break;
- cout << "Password invalid. Try again." << endl;
- }
- }
- else
- {
- while (masterPassword.empty())
+ else if (arg == "--password" && i + 1 < argc)
+ passwordsToNote.push_back(argv[++i]);
+ else if (arg == "--master" && i + 1 < argc)
+ masterPassword = argv[++i];
+ else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
{
- masterPassword = getPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
- string confirm = getPassword("Please confirm the password by entering it again: ");
- if (masterPassword != confirm)
- {
- cout << "Passwords were different. Try again." << endl;
- masterPassword.clear();
- }
+ mode = OperationMode::Import;
+ filename = argv[++i];
}
- keyManager.create(masterPassword);
- }
-
- for (auto const& s: toImport)
- {
- keyManager.import(s, "Imported key (UNSAFE)");
- if (!signingKey)
- signingKey = toAddress(s);
- }
-
- if (keyManager.accounts().empty())
- keyManager.import(Secret::random(), "Default key");
-
- cout << ethCredits();
- web3.setIdealPeerCount(peers);
-// std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
- std::shared_ptr gasPricer = make_shared(askPrice, bidPrice);
- eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr;
- StructuredLogger::starting(WebThreeDirect::composeClientVersion("++eth", clientName), dev::Version);
- if (c)
- {
- c->setGasPricer(gasPricer);
- c->setForceMining(forceMining);
- c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
- c->setAddress(beneficiary);
- c->setNetworkId(networkId);
- }
-
- cout << "Transaction Signer: " << signingKey << endl;
- cout << "Mining Benefactor: " << beneficiary << endl;
-
- if (bootstrap || !remoteHost.empty())
- {
- web3.startNetwork();
- cout << "Node ID: " << web3.enode() << endl;
- }
- else
- cout << "Networking disabled. To start, use netstart or pass -b or a remote host." << endl;
-
-#if ETH_JSONRPC || !ETH_TRUE
- shared_ptr jsonrpcServer;
- unique_ptr jsonrpcConnector;
- if (jsonrpc > -1)
- {
- jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
- jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer));
- jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; });
- jsonrpcServer->StartListening();
- if (jsonAdmin.empty())
- jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}});
- else
- jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}});
- cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl;
- }
-#endif
-
- if (bootstrap)
- for (auto const& i: Host::pocHosts())
- web3.requirePeer(i.first, i.second);
- if (!remoteHost.empty())
- web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
-
- signal(SIGABRT, &sighandler);
- signal(SIGTERM, &sighandler);
- signal(SIGINT, &sighandler);
-
- if (interactive)
- {
- additional = "Press Enter";
- string l;
- while (!g_exit)
+ else if (arg == "--dont-check")
+ safeImport = true;
+ else if ((arg == "-E" || arg == "--export") && i + 1 < argc)
{
- g_silence = false;
- cout << logbuf << "Press Enter" << flush;
- std::getline(cin, l);
- logbuf.clear();
- g_silence = true;
-
-#if ETH_READLINE
- if (l.size())
- add_history(l.c_str());
- if (auto c = readline("> "))
- {
- l = c;
- free(c);
- }
- else
- break;
-#else
- string l;
- cout << "> " << flush;
- std::getline(cin, l);
-#endif
- istringstream iss(l);
- string cmd;
- iss >> cmd;
- boost::to_lower(cmd);
- if (cmd == "netstart")
- {
- iss >> netPrefs.listenPort;
- web3.setNetworkPreferences(netPrefs);
- web3.startNetwork();
- }
- else if (cmd == "connect")
- {
- string addrPort;
- iss >> addrPort;
- web3.addNode(p2p::NodeId(), addrPort);
- }
- else if (cmd == "netstop")
+ mode = OperationMode::Export;
+ filename = argv[++i];
+ }
+ else if (arg == "--prime" && i + 1 < argc)
+ try
{
- web3.stopNetwork();
+ prime = stoi(argv[++i]);
}
- else if (c && cmd == "minestart")
+ catch (...)
{
- c->startMining();
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "minestop")
+ else if (arg == "--yes-i-really-know-what-im-doing")
+ yesIReallyKnowWhatImDoing = true;
+ else if (arg == "--sentinel" && i + 1 < argc)
+ sentinel = argv[++i];
+ else if (arg == "--mine-on-wrong-chain")
+ mineOnWrongChain = true;
+ else if (arg == "--format" && i + 1 < argc)
+ {
+ string m = argv[++i];
+ if (m == "binary")
+ exportFormat = Format::Binary;
+ else if (m == "hex")
+ exportFormat = Format::Hex;
+ else if (m == "human")
+ exportFormat = Format::Human;
+ else
{
- c->stopMining();
+ cerr << "Bad " << arg << " option: " << m << endl;
+ return -1;
}
- else if (c && cmd == "mineforce")
+ }
+ else if (arg == "--to" && i + 1 < argc)
+ exportTo = argv[++i];
+ else if (arg == "--from" && i + 1 < argc)
+ exportFrom = argv[++i];
+ else if (arg == "--only" && i + 1 < argc)
+ exportTo = exportFrom = argv[++i];
+ else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc)
+ {
+ if (arg == "-n")
+ cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use --upnp instead." << endl;
+ string m = argv[++i];
+ if (isTrue(m))
+ upnp = true;
+ else if (isFalse(m))
+ upnp = false;
+ else
{
- string enable;
- iss >> enable;
- c->setForceMining(isTrue(enable));
+ cerr << "Bad " << arg << " option: " << m << endl;
+ return -1;
}
-/* else if (c && cmd == "setblockfees")
- {
- iss >> blockFees;
- try
- {
- gasPricer->setRefBlockFees(u256(blockFees * 1000));
- }
- catch (Overflow const& _e)
- {
- cout << boost::diagnostic_information(_e);
- }
-
- cout << "Block fees: " << blockFees << endl;
+ }
+ else if (arg == "--network-id" && i + 1 < argc)
+ try {
+ networkId = stol(argv[++i]);
}
- else if (c && cmd == "setetherprice")
+ catch (...)
{
- iss >> etherPrice;
- if (etherPrice == 0)
- cout << "ether price cannot be set to zero" << endl;
- else
- {
- try
- {
- gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
- }
- catch (Overflow const& _e)
- {
- cout << boost::diagnostic_information(_e);
- }
- }
- cout << "ether Price: " << etherPrice << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "setpriority")
- {
- string m;
- iss >> m;
- boost::to_lower(m);
- if (m == "lowest")
- priority = TransactionPriority::Lowest;
- else if (m == "low")
- priority = TransactionPriority::Low;
- else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
- priority = TransactionPriority::Medium;
- else if (m == "high")
- priority = TransactionPriority::High;
- else if (m == "highest")
- priority = TransactionPriority::Highest;
- else
- try {
- priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
- }
- catch (...) {
- cerr << "Unknown priority: " << m << endl;
- }
- cout << "Priority: " << (int)priority << "/8" << endl;
- }*/
- else if (cmd == "verbosity")
- {
- if (iss.peek() != -1)
- iss >> g_logVerbosity;
- cout << "Verbosity: " << g_logVerbosity << endl;
+ else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
+ killChain = WithExisting::Kill;
+ else if (arg == "-R" || arg == "--rebuild")
+ killChain = WithExisting::Verify;
+ else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
+ {
+ if (arg == "-c")
+ cerr << "-c is DEPRECATED. It will be removed for the Frontier. Use --client-name instead." << endl;
+ clientName = argv[++i];
+ }
+ else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
+ try {
+ beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
}
-#if ETH_JSONRPC || !ETH_TRUE
- else if (cmd == "jsonport")
+ catch (BadHexCharacter&)
{
- if (iss.peek() != -1)
- iss >> jsonrpc;
- cout << "JSONRPC Port: " << jsonrpc << endl;
+ cerr << "Bad hex in " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (cmd == "jsonstart")
+ catch (...)
{
- if (jsonrpc < 0)
- jsonrpc = SensibleHttpPort;
- jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
- jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer));
- jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; });
- jsonrpcServer->StartListening();
- if (jsonAdmin.empty())
- jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}});
- else
- jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}});
- cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (cmd == "jsonstop")
+ else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
+ {
+ Secret s(fromHex(argv[++i]));
+ toImport.push_back(s);
+ signingKey = toAddress(s);
+ }
+ else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
+ {
+ Secret s(fromHex(argv[++i]));
+ toImport.push_back(s);
+ sessionKey = toAddress(s);
+ }
+ else if ((arg == "--sign-key") && i + 1 < argc)
+ sessionKey = Address(fromHex(argv[++i]));
+ else if ((arg == "--session-sign-key") && i + 1 < argc)
+ sessionKey = Address(fromHex(argv[++i]));
+ else if (arg == "--structured-logging-format" && i + 1 < argc)
+ structuredLoggingFormat = string(argv[++i]);
+ else if (arg == "--structured-logging")
+ structuredLogging = true;
+ else if (arg == "--structured-logging-url" && i + 1 < argc)
+ {
+ structuredLogging = true;
+ structuredLoggingURL = argv[++i];
+ }
+ else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
+ dbPath = argv[++i];
+ else if (arg == "--genesis-nonce" && i + 1 < argc)
+ {
+ try
{
- if (jsonrpcServer.get())
- jsonrpcServer->StopListening();
- jsonrpcServer.reset();
+ CanonBlockChain::setGenesisNonce(Nonce(argv[++i]));
}
-#endif
- else if (cmd == "address")
+ catch (...)
{
- cout << "Current mining beneficiary:" << endl << beneficiary << endl;
- cout << "Current signing account:" << endl << signingKey << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "blockhashfromnumber")
+ }
+/* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
+ {
+ try
{
- if (iss.peek() != -1)
- {
- unsigned number;
- iss >> number;
- cout << " hash of block: " << c->hashFromNumber(number).hex() << endl;
- }
+ blockFees = stof(argv[++i]);
}
- else if (c && cmd == "numberfromblockhash")
+ catch (...)
{
- if (iss.peek() != -1)
- {
- string stringHash;
- iss >> stringHash;
-
- h256 hash = h256(fromHex(stringHash));
- cout << " number of block: " << c->numberFromHash(hash) << endl;
- }
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "block")
+ }
+ else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
+ {
+ try
{
- cout << "Current block: " << c->blockChain().details().number << endl;
+ etherPrice = stof(argv[++i]);
}
- else if (c && cmd == "blockqueue")
+ catch (...)
{
- cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "findblock")
+ }*/
+ else if (arg == "--ask" && i + 1 < argc)
+ {
+ try
{
- if (iss.peek() != -1)
- {
- string stringHash;
- iss >> stringHash;
-
- h256 hash = h256(fromHex(stringHash));
-
- // search in blockchain
- cout << "search in blockchain... " << endl;
- try
- {
- cout << c->blockInfo(hash) << endl;
- }
- catch(Exception& _e)
- {
- cout << "block not in blockchain" << endl;
- cout << boost::diagnostic_information(_e) << endl;
- }
-
- cout << "search in blockqueue... " << endl;
-
- switch(c->blockQueue().blockStatus(hash))
- {
- case QueueStatus::Ready:
- cout << "Ready" << endl;
- break;
- case QueueStatus::Importing:
- cout << "Importing" << endl;
- break;
- case QueueStatus::UnknownParent:
- cout << "UnknownParent" << endl;
- break;
- case QueueStatus::Bad:
- cout << "Bad" << endl;
- break;
- case QueueStatus::Unknown:
- cout << "Unknown" << endl;
- break;
- default:
- cout << "invalid queueStatus" << endl;
- }
- }
- else
- cwarn << "Require parameter: findblock HASH";
+ askPrice = u256(argv[++i]);
}
- else if (c && cmd == "firstunknown")
+ catch (...)
{
- cout << "first unknown blockhash: " << c->blockQueue().firstUnknown().hex() << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (c && cmd == "retryunknown")
+ }
+ else if (arg == "--bid" && i + 1 < argc)
+ {
+ try
{
- c->retryUnknown();
+ bidPrice = u256(argv[++i]);
}
- else if (cmd == "peers")
+ catch (...)
{
- for (auto it: web3.peers())
- cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
- << std::chrono::duration_cast(it.lastPing).count() << "ms"
- << endl;
+ cerr << "Bad " << arg << " option: " << argv[i] << endl;
+ return -1;
}
- else if (cmd == "newaccount")
- {
- string name;
- std::getline(iss, name);
- auto s = Secret::random();
- string password;
- while (password.empty())
- {
- password = getPassword("Please enter a password to protect this key (press enter for protection only be the MASTER password/keystore): ");
- string confirm = getPassword("Please confirm the password by entering it again: ");
- if (password != confirm)
- {
- cout << "Passwords were different. Try again." << endl;
- password.clear();
- }
+ }
+ else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
+ {
+ string m = boost::to_lower_copy(string(argv[++i]));
+ if (m == "lowest")
+ priority = TransactionPriority::Lowest;
+ else if (m == "low")
+ priority = TransactionPriority::Low;
+ else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
+ priority = TransactionPriority::Medium;
+ else if (m == "high")
+ priority = TransactionPriority::High;
+ else if (m == "highest")
+ priority = TransactionPriority::Highest;
+ else
+ try {
+ priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
- if (!password.empty())
- {
- cout << "Enter a hint for this password: " << flush;
- string hint;
- std::getline(cin, hint);
- keyManager.import(s, name, password, hint);
+ catch (...) {
+ cerr << "Unknown " << arg << " option: " << m << endl;
+ return -1;
}
- else
- keyManager.import(s, name);
- cout << "New account created: " << toAddress(s);
- }
- else if (c && cmd == "accounts")
- {
- cout << "Accounts:" << endl;
- u256 total = 0;
- for (auto const& address: keyManager.accounts())
- {
- auto b = c->balanceAt(address);
- cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl;
- total += b;
+ }
+ else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
+ {
+ string m = argv[++i];
+ if (isTrue(m))
+ mining = ~(unsigned)0;
+ else if (isFalse(m))
+ mining = 0;
+ else
+ try {
+ mining = stoi(m);
}
- cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
- }
- else if (c && cmd == "transact")
- {
- auto const& bc =c->blockChain();
- auto h = bc.currentHash();
- auto blockData = bc.block(h);
- BlockInfo info(blockData);
- if (iss.peek() != -1)
- {
- string hexAddr;
- u256 amount;
- u256 gasPrice;
- u256 gas;
- string sechex;
- string sdata;
-
- iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
-
- if (!gasPrice)
- gasPrice = gasPricer->bid(priority);
-
- cnote << "Data:";
- cnote << sdata;
- bytes data = dev::eth::parseData(sdata);
- cnote << "Bytes:";
- string sbd = asString(data);
- bytes bbd = asBytes(sbd);
- stringstream ssbd;
- ssbd << bbd;
- cnote << ssbd.str();
- int ssize = sechex.length();
- int size = hexAddr.length();
- u256 minGas = (u256)Transaction::gasRequired(data, 0);
- if (size < 40)
- {
- if (size > 0)
- cwarn << "Invalid address length:" << size;
- }
- else if (gas < minGas)
- cwarn << "Minimum gas amount is" << minGas;
- else if (ssize < 40)
- {
- if (ssize > 0)
- cwarn << "Invalid secret length:" << ssize;
- }
- else
- {
- try
- {
- Secret secret = h256(fromHex(sechex));
- Address dest = h160(fromHex(hexAddr));
- c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, transaction rejected";
- cwarn << boost::diagnostic_information(_e);
- }
- catch (...)
- {
- cwarn << "transaction rejected";
- }
- }
+ catch (...) {
+ cerr << "Unknown " << arg << " option: " << m << endl;
+ return -1;
}
- else
- cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
- }
-
- else if (c && cmd == "transactnonce")
+ }
+ else if (arg == "-b" || arg == "--bootstrap")
+ bootstrap = true;
+ else if (arg == "--no-discovery")
+ disableDiscovery = true;
+ else if (arg == "--pin")
+ pinning = true;
+ else if (arg == "-f" || arg == "--force-mining")
+ forceMining = true;
+ else if (arg == "-i" || arg == "--interactive")
+ interactive = true;
+#if ETH_JSONRPC
+ else if ((arg == "-j" || arg == "--json-rpc"))
+ jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
+ else if (arg == "--json-rpc-port" && i + 1 < argc)
+ jsonrpc = atoi(argv[++i]);
+ else if (arg == "--json-admin" && i + 1 < argc)
+ jsonAdmin = argv[++i];
+#endif
+#if ETH_JSCONSOLE
+ else if (arg == "--console")
+ useConsole = true;
+#endif
+ else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
+ g_logVerbosity = atoi(argv[++i]);
+ else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
+ peers = atoi(argv[++i]);
+ else if ((arg == "-o" || arg == "--mode") && i + 1 < argc)
+ {
+ string m = argv[++i];
+ if (m == "full")
+ nodeMode = NodeMode::Full;
+ else if (m == "peer")
+ nodeMode = NodeMode::PeerServer;
+ else
{
- auto const& bc =c->blockChain();
- auto h = bc.currentHash();
- auto blockData = bc.block(h);
- BlockInfo info(blockData);
- if (iss.peek() != -1)
- {
- string hexAddr;
- u256 amount;
- u256 gasPrice;
- u256 gas;
- string sechex;
- string sdata;
- u256 nonce;
-
- iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata >> nonce;
-
- if (!gasPrice)
- gasPrice = gasPricer->bid(priority);
-
- cnote << "Data:";
- cnote << sdata;
- bytes data = dev::eth::parseData(sdata);
- cnote << "Bytes:";
- string sbd = asString(data);
- bytes bbd = asBytes(sbd);
- stringstream ssbd;
- ssbd << bbd;
- cnote << ssbd.str();
- int ssize = sechex.length();
- int size = hexAddr.length();
- u256 minGas = (u256)Transaction::gasRequired(data, 0);
- if (size < 40)
- {
- if (size > 0)
- cwarn << "Invalid address length:" << size;
- }
- else if (gas < minGas)
- cwarn << "Minimum gas amount is" << minGas;
- else if (ssize < 40)
- {
- if (ssize > 0)
- cwarn << "Invalid secret length:" << ssize;
- }
- else
- {
- try
- {
- Secret secret = h256(fromHex(sechex));
- Address dest = h160(fromHex(hexAddr));
- c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce);
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, transaction rejected";
- cwarn << boost::diagnostic_information(_e);
- }
- catch (...)
- {
- cwarn << "transaction rejected";
- }
- }
- }
- else
- cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA NONCE";
+ cerr << "Unknown mode: " << m << endl;
+ return -1;
}
+ }
+#if ETH_EVMJIT
+ else if (arg == "-J" || arg == "--jit")
+ jit = true;
+#endif
+ else if (arg == "-h" || arg == "--help")
+ help();
+ else if (arg == "-V" || arg == "--version")
+ version();
+ else
+ {
+ cerr << "Invalid argument: " << arg << endl;
+ exit(-1);
+ }
+ }
- else if (c && cmd == "txcreate")
- {
- auto const& bc =c->blockChain();
- auto h = bc.currentHash();
- auto blockData = bc.block(h);
- BlockInfo info(blockData);
- if (iss.peek() != -1)
- {
- u256 amount;
- u256 gasPrice;
- u256 gas;
- string sechex;
- string sdata;
-
- iss >> amount >> gasPrice >> gas >> sechex >> sdata;
-
- if (!gasPrice)
- gasPrice = gasPricer->bid(priority);
-
- cnote << "Data:";
- cnote << sdata;
- bytes data = dev::eth::parseData(sdata);
- cnote << "Bytes:";
- string sbd = asString(data);
- bytes bbd = asBytes(sbd);
- stringstream ssbd;
- ssbd << bbd;
- cnote << ssbd.str();
- int ssize = sechex.length();
- u256 minGas = (u256)Transaction::gasRequired(data, 0);
- if (gas < minGas)
- cwarn << "Minimum gas amount is" << minGas;
- else if (ssize < 40)
- {
- if (ssize > 0)
- cwarn << "Invalid secret length:" << ssize;
- }
- else
- {
- try
- {
- Secret secret = h256(fromHex(sechex));
- cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, transaction rejected";
- cwarn << boost::diagnostic_information(_e);
- }
- catch (...)
- {
- cwarn << "transaction rejected";
- }
- }
- }
- else
- cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT";
- }
-#if ETH_FATDB
- else if (c && cmd == "listcontracts")
- {
- auto acs =c->addresses();
- string ss;
- for (auto const& i: acs)
- if ( c->codeAt(i, PendingBlock).size())
- {
- ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
- cout << ss << endl;
- }
- }
- else if (c && cmd == "listaccounts")
+ m.execute();
+
+ KeyManager keyManager;
+ for (auto const& s: passwordsToNote)
+ keyManager.notePassword(s);
+
+ {
+ RLPStream config(2);
+ config << signingKey << beneficiary;
+ writeFile(configFile, config.out());
+ }
+
+ if (sessionKey)
+ signingKey = sessionKey;
+
+ if (!clientName.empty())
+ clientName += "/";
+
+ string logbuf;
+ std::string additional;
+ if (interactive)
+ g_logPost = [&](std::string const& a, char const*){
+ static SpinLock s_lock;
+ SpinGuard l(s_lock);
+
+ if (g_silence)
+ logbuf += a + "\n";
+ else
+ cout << "\r \r" << a << endl << additional << flush;
+
+ // helpful to use OutputDebugString on windows
+ #ifdef _WIN32
{
- auto acs =c->addresses();
- string ss;
- for (auto const& i: acs)
- if ( c->codeAt(i, PendingBlock).empty())
- {
- ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
- cout << ss << endl;
- }
+ OutputDebugStringA(a.data());
+ OutputDebugStringA("\n");
}
- else if (c && cmd == "balanceat")
- {
- if (iss.peek() != -1)
- {
- string stringHash;
- iss >> stringHash;
+ #endif
+ };
- Address address = h160(fromHex(stringHash));
+ auto getPassword = [&](string const& prompt){
+ auto s = g_silence;
+ g_silence = true;
+ cout << endl;
+ string ret = dev::getPassword(prompt);
+ g_silence = s;
+ return ret;
+ };
+ auto getAccountPassword = [&](Address const& a){
+ return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): ");
+ };
- cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl;
- }
- }
- else if (c && cmd == "balanceatblock")
+ StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
+ VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
+ auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
+ netPrefs.discovery = !disableDiscovery;
+ netPrefs.pin = pinning;
+ auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
+ dev::WebThreeDirect web3(
+ WebThreeDirect::composeClientVersion("++eth", clientName),
+ dbPath,
+ killChain,
+ nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(),
+ netPrefs,
+ &nodesState);
+ web3.ethereum()->setMineOnBadChain(mineOnWrongChain);
+ web3.ethereum()->setSentinel(sentinel);
+
+ auto toNumber = [&](string const& s) -> unsigned {
+ if (s == "latest")
+ return web3.ethereum()->number();
+ if (s.size() == 64 || (s.size() == 66 && s.substr(0, 2) == "0x"))
+ return web3.ethereum()->blockChain().number(h256(s));
+ try {
+ return stol(s);
+ }
+ catch (...)
+ {
+ cerr << "Bad block number/hash option: " << s << endl;
+ exit(-1);
+ }
+ };
+
+ if (mode == OperationMode::Export)
+ {
+ ofstream fout(filename, std::ofstream::binary);
+ ostream& out = (filename.empty() || filename == "--") ? cout : fout;
+
+ unsigned last = toNumber(exportTo);
+ for (unsigned i = toNumber(exportFrom); i <= last; ++i)
+ {
+ bytes block = web3.ethereum()->blockChain().block(web3.ethereum()->blockChain().numberHash(i));
+ switch (exportFormat)
{
- if (iss.peek() != -1)
- {
- string stringHash;
- unsigned blocknumber;
- iss >> stringHash >> blocknumber;
-
- Address address = h160(fromHex(stringHash));
-
- cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address, blocknumber)) << endl;
- }
+ case Format::Binary: out.write((char const*)block.data(), block.size()); break;
+ case Format::Hex: out << toHex(block) << endl; break;
+ case Format::Human: out << RLP(block) << endl; break;
+ default:;
}
- else if (c && cmd == "storageat")
- {
- if (iss.peek() != -1)
- {
- string stringHash;
- iss >> stringHash;
+ }
+ return 0;
+ }
- Address address = h160(fromHex(stringHash));
+ if (mode == OperationMode::Import)
+ {
+ ifstream fin(filename, std::ifstream::binary);
+ istream& in = (filename.empty() || filename == "--") ? cin : fin;
+ unsigned alreadyHave = 0;
+ unsigned good = 0;
+ unsigned futureTime = 0;
+ unsigned unknownParent = 0;
+ unsigned bad = 0;
+ chrono::steady_clock::time_point t = chrono::steady_clock::now();
+ double last = 0;
+ unsigned lastImported = 0;
+ unsigned imported = 0;
+ while (in.peek() != -1)
+ {
+ bytes block(8);
+ in.read((char*)block.data(), 8);
+ block.resize(RLP(block, RLP::LaissezFaire).actualSize());
+ in.read((char*)block.data() + 8, block.size() - 8);
- cout << "storage at " << stringHash << " is: " << endl;
- for (auto s: c->storageAt(address))
- cout << toHex(s.first) << " : " << toHex(s.second) << endl;
- }
- }
- else if (c && cmd == "storageatblock")
+ switch (web3.ethereum()->queueBlock(block, safeImport))
{
- if (iss.peek() != -1)
- {
- string stringHash;
- unsigned blocknumber;
- iss >> stringHash >> blocknumber;
-
- Address address = h160(fromHex(stringHash));
-
- cout << "storage at " << stringHash << " is: " << endl;
- for (auto s: c->storageAt(address, blocknumber))
- cout << "\"0x" << toHex(s.first) << "\" : \"0x" << toHex(s.second) << "\"," << endl;
- }
+ case ImportResult::Success: good++; break;
+ case ImportResult::AlreadyKnown: alreadyHave++; break;
+ case ImportResult::UnknownParent: unknownParent++; break;
+ case ImportResult::FutureTimeUnknown: unknownParent++; futureTime++; break;
+ case ImportResult::FutureTimeKnown: futureTime++; break;
+ default: bad++; break;
}
- else if (c && cmd == "codeat")
- {
- if (iss.peek() != -1)
- {
- string stringHash;
- iss >> stringHash;
- Address address = h160(fromHex(stringHash));
+ // sync chain with queue
+ tuple r = web3.ethereum()->syncQueue(10);
+ imported += get<2>(r);
- cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl;
- }
+ double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0;
+ if ((unsigned)e >= last + 10)
+ {
+ auto i = imported - lastImported;
+ auto d = e - last;
+ cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
+ last = (unsigned)e;
+ lastImported = imported;
+// cout << web3.ethereum()->blockQueueStatus() << endl;
}
-#endif
+ }
- else if (c && cmd == "send")
- {
- if (iss.peek() != -1)
- {
- string hexAddr;
- u256 amount;
+ while (web3.ethereum()->blockQueue().items().first + web3.ethereum()->blockQueue().items().second > 0)
+ {
+ this_thread::sleep_for(chrono::seconds(1));
+ web3.ethereum()->syncQueue(100000);
+ }
+ double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0;
+ cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
+ return 0;
+ }
- iss >> hexAddr >> amount;
- int size = hexAddr.length();
- if (size < 40)
- {
- if (size > 0)
- cwarn << "Invalid address length:" << size;
- }
- else
- {
- auto const& bc =c->blockChain();
- auto h = bc.currentHash();
- auto blockData = bc.block(h);
- BlockInfo info(blockData);
- u256 minGas = (u256)Transaction::gasRequired(bytes(), 0);
- try
- {
- Address dest = h160(fromHex(hexAddr, WhenError::Throw));
- c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), amount, dest, bytes(), minGas);
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, transaction rejected";
- cwarn << boost::diagnostic_information(_e);
- }
- catch (...)
- {
- cwarn << "transaction rejected";
- }
- }
- }
- else
- cwarn << "Require parameters: send ADDRESS AMOUNT";
- }
- else if (c && cmd == "contract")
- {
- auto const& bc =c->blockChain();
- auto h = bc.currentHash();
- auto blockData = bc.block(h);
- BlockInfo info(blockData);
- if (iss.peek() != -1)
- {
- u256 endowment;
- u256 gas;
- u256 gasPrice;
- string sinit;
- iss >> endowment >> gasPrice >> gas >> sinit;
- trim_all(sinit);
- int size = sinit.length();
- bytes init;
- cnote << "Init:";
- cnote << sinit;
- cnote << "Code size:" << size;
- if (size < 1)
- cwarn << "No code submitted";
- else
- {
- cnote << "Assembled:";
- stringstream ssc;
- try
- {
- init = fromHex(sinit, WhenError::Throw);
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, code rejected";
- cwarn << boost::diagnostic_information(_e);
- init = bytes();
- }
- catch (...)
- {
- cwarn << "code rejected";
- init = bytes();
- }
- ssc.str(string());
- ssc << disassemble(init);
- cnote << "Init:";
- cnote << ssc.str();
- }
- u256 minGas = (u256)Transaction::gasRequired(init, 0);
- if (!init.size())
- cwarn << "Contract creation aborted, no init code.";
- else if (endowment < 0)
- cwarn << "Invalid endowment";
- else if (gas < minGas)
- cwarn << "Minimum gas amount is" << minGas;
- else
- c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), endowment, init, gas, gasPrice);
- }
- else
- cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
- }
- else if (c && cmd == "dumpreceipt")
- {
- unsigned block;
- unsigned index;
- iss >> block >> index;
- dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
- auto rb = r.rlp();
- cout << "RLP: " << RLP(rb) << endl;
- cout << "Hex: " << toHex(rb) << endl;
- cout << r << endl;
- }
- else if (c && cmd == "reprocess")
- {
- string block;
- iss >> block;
- h256 blockHash;
+ if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing)
+ {
+ auto pd = contents(getDataDir() + "primes");
+ unordered_set primes = RLP(pd).toUnorderedSet();
+ while (true)
+ {
+ if (!prime)
try
{
- if (block.size() == 64 || block.size() == 66)
- blockHash = h256(block);
- else
- blockHash = c->blockChain().numberHash(stoi(block));
- c->state(blockHash);
- }
- catch (...)
- {}
- }
- else if (c && cmd == "dumptrace")
- {
- unsigned block;
- unsigned index;
- string filename;
- string format;
- iss >> block >> index >> filename >> format;
- ofstream f;
- f.open(filename);
-
- dev::eth::State state = c->state(index + 1,c->blockChain().numberHash(block));
- if (index < state.pending().size())
- {
- Executive e(state, c->blockChain(), 0);
- Transaction t = state.pending()[index];
- state = state.fromPending(index);
- try
- {
- OnOpFunc oof;
- if (format == "pretty")
- oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
- {
- dev::eth::VM* vm = vvm;
- dev::eth::ExtVM const* ext = static_cast(vextVM);
- f << endl << " STACK" << endl;
- for (auto i: vm->stack())
- f << (h256)i << endl;
- f << " MEMORY" << endl << dev::memDump(vm->memory());
- f << " STORAGE" << endl;
- for (auto const& i: ext->state().storage(ext->myAddress))
- f << showbase << hex << i.first << ": " << i.second << endl;
- f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << gas << " | -" << dec << gasCost << " | " << newMemSize << "x32";
- };
- else if (format == "standard")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
- {
- dev::eth::VM* vm = vvm;
- dev::eth::ExtVM const* ext = static_cast(vextVM);
- f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
- };
- else if (format == "standard+")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
- {
- dev::eth::VM* vm = vvm;
- dev::eth::ExtVM const* ext = static_cast(vextVM);
- if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
- for (auto const& i: ext->state().storage(ext->myAddress))
- f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
- f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
- };
- e.initialize(t);
- if (!e.execute())
- e.go(oof);
- e.finalize();
- }
- catch(Exception const& _e)
- {
- // TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain.
- cwarn << diagnostic_information(_e);
- }
+ prime = stoi(getPassword("To enter the Frontier, enter a 6 digit prime that you have not entered before: "));
}
- }
- else if (c && cmd == "inspect")
- {
- string rechex;
- iss >> rechex;
-
- if (rechex.length() != 40)
- cwarn << "Invalid address length";
- else
- {
- auto h = h160(fromHex(rechex));
- stringstream s;
+ catch (...) {}
+ if (isPrime(prime) && !primes.count(prime))
+ break;
+ prime = 0;
+ }
+ primes.insert(prime);
+ writeFile(getDataDir() + "primes", rlp(primes));
+ }
- try
- {
- auto storage =c->storageAt(h, PendingBlock);
- for (auto const& i: storage)
- s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
- s << endl << disassemble( c->codeAt(h, PendingBlock)) << endl;
-
- string outFile = getDataDir() + "/" + rechex + ".evm";
- ofstream ofs;
- ofs.open(outFile, ofstream::binary);
- ofs.write(s.str().c_str(), s.str().length());
- ofs.close();
-
- cnote << "Saved" << rechex << "to" << outFile;
- }
- catch (dev::InvalidTrie)
- {
- cwarn << "Corrupted trie.";
- }
- }
- }
- else if (cmd == "setsigningkey")
- {
- if (iss.peek() != -1)
- {
- string hexSec;
- iss >> hexSec;
- signingKey = Address(fromHex(hexSec));
- }
- else
- cwarn << "Require parameter: setSecret HEXSECRETKEY";
- }
- else if (cmd == "setaddress")
- {
- if (iss.peek() != -1)
- {
- string hexAddr;
- iss >> hexAddr;
- if (hexAddr.length() != 40)
- cwarn << "Invalid address length: " << hexAddr.length();
- else
- {
- try
- {
- beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
- }
- catch (BadHexCharacter& _e)
- {
- cwarn << "invalid hex character, coinbase rejected";
- cwarn << boost::diagnostic_information(_e);
- }
- catch (...)
- {
- cwarn << "coinbase rejected";
- }
- }
- }
- else
- cwarn << "Require parameter: setAddress HEXADDRESS";
- }
- else if (cmd == "exportconfig")
+ if (keyManager.exists())
+ {
+ if (masterPassword.empty() || !keyManager.load(masterPassword))
+ while (true)
{
- if (iss.peek() != -1)
- {
- string path;
- iss >> path;
- RLPStream config(2);
- config << signingKey << beneficiary;
- writeFile(path, config.out());
- }
- else
- cwarn << "Require parameter: exportConfig PATH";
+ masterPassword = getPassword("Please enter your MASTER password: ");
+ if (keyManager.load(masterPassword))
+ break;
+ cout << "Password invalid. Try again." << endl;
}
- else if (cmd == "importconfig")
+ }
+ else
+ {
+ while (masterPassword.empty())
+ {
+ masterPassword = getPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
+ string confirm = getPassword("Please confirm the password by entering it again: ");
+ if (masterPassword != confirm)
{
- if (iss.peek() != -1)
- {
- string path;
- iss >> path;
- bytes b = contents(path);
- if (b.size())
- {
- RLP config(b);
- signingKey = config[0].toHash();
- beneficiary = config[1].toHash();
- }
- else
- cwarn << path << "has no content!";
- }
- else
- cwarn << "Require parameter: importConfig PATH";
+ cout << "Passwords were different. Try again." << endl;
+ masterPassword.clear();
}
- else if (cmd == "help")
- interactiveHelp();
- else if (cmd == "exit")
- break;
- else
- cout << "Unrecognised command. Type 'help' for help in interactive mode." << endl;
}
-#if ETH_JSONRPC
- if (jsonrpcServer.get())
- jsonrpcServer->StopListening();
-#endif
+ keyManager.create(masterPassword);
+ }
+
+ for (auto const& s: toImport)
+ {
+ keyManager.import(s, "Imported key (UNSAFE)");
+ if (!signingKey)
+ signingKey = toAddress(s);
+ }
+
+ if (keyManager.accounts().empty())
+ keyManager.import(Secret::random(), "Default key");
+
+ cout << ethCredits();
+ web3.setIdealPeerCount(peers);
+// std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
+ std::shared_ptr gasPricer = make_shared(askPrice, bidPrice);
+ eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr;
+ StructuredLogger::starting(WebThreeDirect::composeClientVersion("++eth", clientName), dev::Version);
+ if (c)
+ {
+ c->setGasPricer(gasPricer);
+ c->setForceMining(forceMining);
+ c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
+ c->setAddress(beneficiary);
+ c->setNetworkId(networkId);
+ }
+
+ cout << "Transaction Signer: " << signingKey << endl;
+ cout << "Mining Benefactor: " << beneficiary << endl;
+
+ if (bootstrap || !remoteHost.empty())
+ {
+ web3.startNetwork();
+ cout << "Node ID: " << web3.enode() << endl;
+ }
+ else
+ cout << "Networking disabled. To start, use netstart or pass -b or a remote host." << endl;
+
+ if (useConsole && jsonrpc == -1)
+ jsonrpc = SensibleHttpPort;
+
+#if ETH_JSONRPC || !ETH_TRUE
+ shared_ptr jsonrpcServer;
+ unique_ptr jsonrpcConnector;
+ if (jsonrpc > -1)
+ {
+ jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
+ jsonrpcServer = make_shared(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer);
+ jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; });
+ jsonrpcServer->StartListening();
+ if (jsonAdmin.empty())
+ jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}});
+ else
+ jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}});
+ cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl;
}
+#endif
+
+ if (bootstrap)
+ for (auto const& i: Host::pocHosts())
+ web3.requirePeer(i.first, i.second);
+ if (!remoteHost.empty())
+ web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
+
+ signal(SIGABRT, &sighandler);
+ signal(SIGTERM, &sighandler);
+ signal(SIGINT, &sighandler);
+
+ if (interactive)
+ interactiveMode(c, gasPricer, web3, keyManager, logbuf, additional, getPassword, getAccountPassword, netPrefs, beneficiary, signingKey, priority);
else if (c)
{
- unsigned n =c->blockChain().details().number;
+ unsigned n = c->blockChain().details().number;
if (mining)
c->startMining();
if (useConsole)
{
-#if ETH_JSCONSOLE
+#if ETH_JSCONSOLE || !ETH_TRUE
JSLocalConsole console;
-
- jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer));
- jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; });
- jsonrpcServer->StartListening();
- if (jsonAdmin.empty())
- jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}});
- else
- jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}});
- cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl;
-
+ // TODO: set port properly?
while (!g_exit)
{
console.readExpression();
stopMiningAfterXBlocks(c, n, mining);
}
-
jsonrpcServer->StopListening();
#endif
}
@@ -1856,9 +1753,15 @@ int main(int argc, char** argv)
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
+#if ETH_JSONRPC
+ if (jsonrpcServer.get())
+ jsonrpcServer->StopListening();
+#endif
+
StructuredLogger::stopping(WebThreeDirect::composeClientVersion("++eth", clientName), dev::Version);
auto netData = web3.saveNetwork();
if (!netData.empty())
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData);
return 0;
}
+
diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h
index ae8eaed92..af7d8e048 100644
--- a/ethkey/KeyAux.h
+++ b/ethkey/KeyAux.h
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include "BuildInfo.h"
using namespace std;
using namespace dev;
@@ -105,7 +106,9 @@ public:
ImportWithAddress,
Export,
Recode,
- Kill
+ Kill,
+ SignTx,
+ DecodeTx,
};
KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {}
@@ -131,8 +134,13 @@ public:
auto v = argv[++i];
m_kdfParams[n] = v;
}
- else if (arg == "--new-bare")
- m_mode = OperationMode::NewBare;
+ else if (arg == "--sign-tx" && i + 1 < argc)
+ {
+ m_mode = OperationMode::SignTx;
+ m_signKey = argv[++i];
+ }
+ else if (arg == "--decode-tx")
+ m_mode = OperationMode::DecodeTx;
else if (arg == "--import-bare")
m_mode = OperationMode::ImportBare;
else if (arg == "--list-bare")
@@ -173,7 +181,7 @@ public:
m_mode = OperationMode::Recode;
else if (arg == "--no-icap")
m_icap = false;
- else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare)
+ else if (m_mode == OperationMode::DecodeTx || m_mode == OperationMode::SignTx || m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare)
m_inputs.push_back(arg);
else
return false;
@@ -209,6 +217,127 @@ public:
}
}
}
+ else if (m_mode == OperationMode::DecodeTx)
+ {
+ string const& i = m_inputs[0];
+ bytes b = fromHex(i);
+ if (b.empty())
+ {
+ std::string s = contentsString(i);
+ b = fromHex(s);
+ if (b.empty())
+ b = asBytes(s);
+ }
+ if (b.empty())
+ cerr << "Unknown file or bad hex: " << i << endl;
+ else
+ try
+ {
+ TransactionBase t(b, CheckTransaction::Everything);
+ cout << "Transaction " << t.sha3().hex() << endl;
+ if (t.isCreation())
+ {
+ cout << " type: creation" << endl;
+ cout << " code: " << toHex(t.data()) << endl;
+ }
+ else
+ {
+ cout << " type: message" << endl;
+ cout << " to: " << t.to().hex() << endl;
+ cout << " data: " << (t.data().empty() ? "none" : toHex(t.data())) << endl;
+ }
+ cout << " from: " << t.from().hex() << endl;
+ cout << " value: " << formatBalance(t.value()) << " (" << t.value() << " wei)" << endl;
+ cout << " nonce: " << t.nonce() << endl;
+ cout << " gas: " << t.gas() << endl;
+ cout << " gas price: " << formatBalance(t.gasPrice()) << " (" << t.gasPrice() << " wei)" << endl;
+ cout << " signing hash: " << t.sha3(WithoutSignature).hex() << endl;
+ cout << " v: " << (int)t.signature().v << endl;
+ cout << " r: " << t.signature().r << endl;
+ cout << " s: " << t.signature().s << endl;
+ }
+ catch (Exception& ex)
+ {
+ cerr << "Invalid transaction: " << ex.what() << endl;
+ }
+ }
+ else if (m_mode == OperationMode::SignTx)
+ {
+ Secret s;
+
+ string json = contentsString(m_signKey);
+ if (!json.empty())
+ {
+ SecretStore store(m_secretsPath);
+ s = Secret(store.secret(store.readKeyContent(json), [&](){ return getPassword("Enter password for key: "); }));
+ }
+ else
+ {
+ if (h128 u = fromUUID(m_signKey))
+ {
+ SecretStore store(m_secretsPath);
+ s = Secret(store.secret(u, [&](){ return getPassword("Enter password for key: "); }));
+ }
+ else if (Address a = Address(m_signKey))
+ {
+ KeyManager wallet(m_walletPath, m_secretsPath);
+ if (wallet.exists())
+ {
+ openWallet(wallet);
+ s = wallet.secret(a, [&](){ return getPassword("Enter password for key: "); });
+ }
+ else
+ {
+ cerr << "Wallet doesn't exist." << endl;
+ exit(-1);
+ }
+ }
+ else
+ {
+ cerr << "Bad file, UUID and address: " << m_signKey << endl;
+ exit(-1);
+ }
+ }
+ if (!s)
+ {
+ cerr << "UUID/address not found: " << m_signKey << endl;
+ exit(-1);
+ }
+
+ for (string const& i: m_inputs)
+ {
+ bytes b = fromHex(i);
+ bool isFile = false;
+ if (b.empty())
+ {
+ isFile = true;
+ std::string s = contentsString(i);
+ b = fromHex(s);
+ if (b.empty())
+ b = asBytes(s);
+ }
+ if (b.empty())
+ cerr << "Unknown file or bad hex: " << i << endl;
+ else
+ try
+ {
+ TransactionBase t(b, CheckTransaction::None);
+ t.sign(s);
+ cout << t.sha3() << ": ";
+ if (isFile)
+ {
+ writeFile(i + ".signed", t.data());
+ cout << i + ".signed" << endl;
+ }
+ else
+ cout << toHex(t.data()) << endl;
+ }
+ catch (Exception& ex)
+ {
+ cerr << "Invalid transaction: " << ex.what() << endl;
+ }
+ }
+ }
else if (m_mode < OperationMode::CreateWallet)
{
SecretStore store(m_secretsPath);
@@ -297,17 +426,7 @@ public:
{
KeyManager wallet(m_walletPath, m_secretsPath);
if (wallet.exists())
- while (true)
- {
- if (wallet.load(m_masterPassword))
- break;
- if (!m_masterPassword.empty())
- {
- cout << "Password invalid. Try again." << endl;
- m_masterPassword.clear();
- }
- m_masterPassword = getPassword("Please enter your MASTER password: ");
- }
+ openWallet(wallet);
else
{
cerr << "Couldn't open wallet. Does it exist?" << endl;
@@ -419,6 +538,10 @@ public:
<< " --wallet-path Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl
<< " -m, --master Specify wallet (master) password." << endl
<< endl
+ << "Transaction operating modes:" << endl
+ << " -d,--decode-tx [|] Decode given transaction." << endl
+ << " -s,--sign-tx [ || ] [ | , ... ] (Re-)Sign given transaction." << endl
+ << endl
<< "Encryption configuration:" << endl
<< " --kdf Specify KDF to use when encrypting (default: sc rypt)" << endl
<< " --kdf-param Specify a parameter for the KDF." << endl
@@ -445,6 +568,21 @@ public:
}
private:
+ void openWallet(KeyManager& _w)
+ {
+ while (true)
+ {
+ if (_w.load(m_masterPassword))
+ break;
+ if (!m_masterPassword.empty())
+ {
+ cout << "Password invalid. Try again." << endl;
+ m_masterPassword.clear();
+ }
+ m_masterPassword = getPassword("Please enter your MASTER password: ");
+ }
+ }
+
KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; }
/// Operating mode.
@@ -468,6 +606,9 @@ private:
/// Importing
strings m_inputs;
+ /// Signing
+ string m_signKey;
+
string m_kdf = "scrypt";
map m_kdfParams;
// string m_cipher;
diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h
index ec6ee57e7..b8305370c 100644
--- a/ethminer/MinerAux.h
+++ b/ethminer/MinerAux.h
@@ -217,7 +217,7 @@ public:
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
- auto r = EthashAux::eval(bi.seedHash(), powHash, bi.nonce);
+ auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index 5450f9311..5591e94bf 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.9.27";
+char const* Version = "0.9.28";
const u256 UndefinedU256 = ~(u256)0;
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index c7fdb6dab..edd14f4a5 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -64,6 +64,8 @@ using byte = uint8_t;
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
+#define DEV_IF_NO_ELSE(X) if(!(X)){}else
+
namespace dev
{
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index ed09e60ee..0faba8e8e 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -50,8 +50,8 @@ enum class HexPrefix
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169"
-template
-std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
+template
+std::string toHex(T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
{
std::ostringstream ret;
unsigned ii = 0;
@@ -99,27 +99,27 @@ bytes asNibbles(bytesConstRef const& _s);
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
-/// @a _Out will typically be either std::string or bytes.
-/// @a _T will typically by unsigned, u160, u256 or bigint.
-template
-inline void toBigEndian(_T _val, _Out& o_out)
+/// @a Out will typically be either std::string or bytes.
+/// @a T will typically by unsigned, u160, u256 or bigint.
+template
+inline void toBigEndian(T _val, Out& o_out)
{
for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
{
- _T v = _val & (_T)0xff;
- o_out[i - 1] = (typename _Out::value_type)(uint8_t)v;
+ T v = _val & (T)0xff;
+ o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
}
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
-/// @a _T will typically by unsigned, u160, u256 or bigint.
-template
-inline _T fromBigEndian(_In const& _bytes)
+/// @a T will typically by unsigned, u160, u256 or bigint.
+template
+inline T fromBigEndian(_In const& _bytes)
{
- _T ret = (_T)0;
+ T ret = (T)0;
for (auto i: _bytes)
- ret = (_T)((ret << 8) | (byte)(typename std::make_unsigned::type)i);
+ ret = (T)((ret << 8) | (byte)(typename std::make_unsigned::type)i);
return ret;
}
@@ -131,11 +131,11 @@ inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); ret
/// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val.
-template
-inline bytes toCompactBigEndian(_T _val, unsigned _min = 0)
+template
+inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
{
int i = 0;
- for (_T v = _val; v; ++i, v >>= 8) {}
+ for (T v = _val; v; ++i, v >>= 8) {}
bytes ret(std::max(_min, i), 0);
toBigEndian(_val, ret);
return ret;
@@ -147,11 +147,11 @@ inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
/// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val.
-template
-inline std::string toCompactBigEndianString(_T _val, unsigned _min = 0)
+template
+inline std::string toCompactBigEndianString(T _val, unsigned _min = 0)
{
int i = 0;
- for (_T v = _val; v; ++i, v >>= 8) {}
+ for (T v = _val; v; ++i, v >>= 8) {}
std::string ret(std::max(_min, i), '\0');
toBigEndian(_val, ret);
return ret;
@@ -179,8 +179,8 @@ std::string escaped(std::string const& _s, bool _all = true);
/// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
-template
-unsigned commonPrefix(_T const& _t, _U const& _u)
+template
+unsigned commonPrefix(T const& _t, _U const& _u)
{
unsigned s = std::min(_t.size(), _u.size());
for (unsigned i = 0;; ++i)
@@ -196,8 +196,8 @@ std::string randomWord();
// General datatype convenience functions.
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
-template
-inline unsigned bytesRequired(_T _i)
+template
+inline unsigned bytesRequired(T _i)
{
unsigned i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
@@ -206,39 +206,39 @@ inline unsigned bytesRequired(_T _i)
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
-template
-void trimFront(_T& _t, unsigned _elements)
+template
+void trimFront(T& _t, unsigned _elements)
{
- static_assert(std::is_pod::value, "");
+ static_assert(std::is_pod::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements);
}
/// Pushes an element on to the front of a collection.
/// Only works for POD element types.
-template
-void pushFront(_T& _t, _U _e)
+template
+void pushFront(T& _t, _U _e)
{
- static_assert(std::is_pod::value, "");
+ static_assert(std::is_pod::value, "");
_t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e;
}
/// Concatenate two vectors of elements of POD types.
-template
-inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b)
+template
+inline std::vector& operator+=(std::vector::value, T>::type>& _a, std::vector const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
- memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
+ memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(T));
return _a;
}
/// Concatenate two vectors of elements.
-template
-inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b)
+template
+inline std::vector& operator+=(std::vector::value, T>::type>& _a, std::vector const& _b)
{
_a.reserve(_a.size() + _b.size());
for (auto& i: _b)
@@ -289,16 +289,16 @@ template std::vector operator+(std::vector _a, U const&
}
/// Concatenate two vectors of elements.
-template
-inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b)
+template
+inline std::vector operator+(std::vector const& _a, std::vector const& _b)
{
- std::vector<_T> ret(_a);
+ std::vector ret(_a);
return ret += _b;
}
/// Merge two sets of elements.
-template
-inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b)
+template
+inline std::set& operator+=(std::set& _a, std::set const& _b)
{
for (auto& i: _b)
_a.insert(i);
@@ -306,13 +306,28 @@ inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b)
}
/// Merge two sets of elements.
-template
-inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
+template
+inline std::set operator+(std::set const& _a, std::set const& _b)
{
- std::set<_T> ret(_a);
+ std::set ret(_a);
return ret += _b;
}
+template
+std::unordered_map& operator+=(std::unordered_map& _x, std::unordered_map const& _y)
+{
+ for (auto const& i: _y)
+ _x.insert(i);
+ return _x;
+}
+
+template
+std::unordered_map operator+(std::unordered_map const& _x, std::unordered_map const& _y)
+{
+ std::unordered_map ret(_x);
+ return ret += _y;
+}
+
/// Make normal string from fixed-length string.
std::string toString(string32 const& _s);
diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp
index 330893c76..92d97aec4 100644
--- a/libdevcore/RLP.cpp
+++ b/libdevcore/RLP.cpp
@@ -320,7 +320,7 @@ std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d)
if (_d.isNull())
_out << "null";
else if (_d.isInt())
- _out << std::showbase << std::hex << std::nouppercase << _d.toInt(RLP::LaisezFaire) << dec;
+ _out << std::showbase << std::hex << std::nouppercase << _d.toInt(RLP::LaissezFaire) << dec;
else if (_d.isData())
_out << escaped(_d.toString(), false);
else if (_d.isList())
diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h
index dee438be4..67f464b9d 100644
--- a/libdevcore/RLP.h
+++ b/libdevcore/RLP.h
@@ -71,7 +71,7 @@ public:
FailIfTooSmall = 16,
Strict = ThrowOnFail | FailIfTooBig,
VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall,
- LaisezFaire = AllowNonCanon
+ LaissezFaire = AllowNonCanon
};
using Strictness = int;
diff --git a/libdevcore/RangeMask.h b/libdevcore/RangeMask.h
index 7c402fc98..eccc8305d 100644
--- a/libdevcore/RangeMask.h
+++ b/libdevcore/RangeMask.h
@@ -24,6 +24,7 @@
#include