Browse Source

Structured logger can output to a file.

Better support of imports/keys and key manager integration for eth.
cl-refactor
Gav Wood 10 years ago
parent
commit
b3f8518716
  1. 148
      eth/main.cpp
  2. 13
      libdevcore/StructuredLogger.cpp
  3. 14
      libdevcore/StructuredLogger.h
  4. 33
      libethereum/BlockChain.cpp
  5. 2
      libethereum/KeyManager.h
  6. 1
      libethereum/State.cpp
  7. 2
      libethereum/State.h

148
eth/main.cpp

@ -91,10 +91,8 @@ void interactiveHelp()
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl
<< " secret Gives the current secret" << endl
<< " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl
<< " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl
<< " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
@ -103,7 +101,7 @@ void interactiveHelp()
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
#endif
<< " setsecret <secret> Set the secret to the hex secret key." << endl
<< " setsigningkey <addr> Set the address with which to sign transactions." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl
@ -127,13 +125,18 @@ void help()
#endif
<< " -K,--kill First kill the blockchain." << endl
<< " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl
<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl
<< " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl
<< endl
<< "Client transacting:" << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< endl
<< "Client mining:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl
@ -143,6 +146,7 @@ void help()
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< endl
<< "Client networking:" << endl
<< " --client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@ -155,12 +159,15 @@ void help()
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< endl
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< endl
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
@ -169,14 +176,17 @@ void help()
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< endl
<< "DAG creation mode:" << endl
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< endl
<< "Import/export modes:" << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl
<< " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
<< " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --only <n> Equivalent to --export-from n --export-to n." << endl
<< endl
<< "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
#if ETH_EVMJIT || !ETH_TRUE
@ -539,13 +549,14 @@ int main(int argc, char** argv)
/// Mining params
unsigned mining = 0;
bool forceMining = false;
KeyPair sigKey = KeyPair::create();
Secret sessionSecret;
Address coinbase = sigKey.address();
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;
@ -570,11 +581,20 @@ int main(int argc, char** argv)
string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile);
strings passwordsToNote;
Secrets toImport;
if (b.size())
{
RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
if (config[0].size() == 32) // secret key - import and forget.
{
Secret s = config[0].toHash<Secret>();
toImport.push_back(s);
}
else // new format - just use it as an address.
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
}
for (int i = 1; i < argc; ++i)
@ -602,6 +622,8 @@ int main(int argc, char** argv)
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]);
}
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)
@ -744,7 +766,7 @@ int main(int argc, char** argv)
}
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
try {
coinbase = h160(fromHex(argv[++i], WhenError::Throw));
beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
}
catch (BadHexCharacter&)
{
@ -760,14 +782,32 @@ int main(int argc, char** argv)
minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU;
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
sigKey = KeyPair(h256(fromHex(argv[++i])));
else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc)
sessionSecret = h256(fromHex(argv[++i]));
/*<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << 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 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-destination" && i + 1 < argc)
structuredLoggingURL = argv[++i];
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
@ -951,16 +991,24 @@ int main(int argc, char** argv)
}
}
KeyManager keyManager;
for (auto const& s: passwordsToNote)
keyManager.notePassword(s);
for (auto const& s: toImport)
{
keyManager.import(s, "Imported key");
if (!signingKey)
signingKey = toAddress(s);
}
{
RLPStream config(2);
config << sigKey.secret() << coinbase;
config << signingKey << beneficiary;
writeFile(configFile, config.out());
}
if (sessionSecret)
sigKey = KeyPair(sessionSecret);
if (sessionKey)
signingKey = sessionKey;
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
@ -985,7 +1033,7 @@ int main(int argc, char** argv)
if (!clientName.empty())
clientName += "/";
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
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);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
@ -1074,12 +1122,12 @@ int main(int argc, char** argv)
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase);
c->setAddress(beneficiary);
c->setNetworkId(networkId);
}
cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
@ -1088,9 +1136,7 @@ int main(int argc, char** argv)
if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
KeyManager keyManager;
if (keyManager.exists())
{
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter your MASTER password: ");
@ -1100,14 +1146,12 @@ int main(int argc, char** argv)
masterPassword.clear();
}
}
}
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: ");
getline(cin, confirm);
if (masterPassword != confirm)
{
cout << "Passwords were different. Try again." << endl;
@ -1123,7 +1167,14 @@ int main(int argc, char** argv)
g_logPost = [&](std::string const& a, char const*) { if (silence) logbuf += a + "\n"; else cout << "\r \r" << a << endl << additional << flush; };
// TODO: give hints &c.
auto getPassword = [&](Address const& a){ auto s = silence; silence = true; cout << endl; string ret = dev::getPassword("Enter password for address " + a.abridged() + ": "); silence = s; return ret; };
auto getPassword = [&](Address const& a){
auto s = silence;
silence = true;
cout << endl;
string ret = dev::getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
silence = s;
return ret;
};
#if ETH_JSONRPC || !ETH_TRUE
shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -1131,7 +1182,7 @@ int main(int argc, char** argv)
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>({sigKey})));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening();
}
#endif
@ -1275,7 +1326,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0)
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>({sigKey})));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening();
}
else if (cmd == "jsonstop")
@ -1287,11 +1338,8 @@ int main(int argc, char** argv)
#endif
else if (cmd == "address")
{
cout << "Current address:" << endl << sigKey.address() << endl;
}
else if (cmd == "secret")
{
cout << "Secret Key: " << sigKey.secret() << endl;
cout << "Current mining beneficiary:" << endl << beneficiary << endl;
cout << "Current signing account:" << endl << signingKey << endl;
}
else if (c && cmd == "block")
{
@ -1306,7 +1354,15 @@ int main(int argc, char** argv)
}
else if (c && cmd == "balance")
{
cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <<c->balanceAt(sigKey.address()) << " wei" << endl;
cout << "Current balance:" << endl;
u256 total = 0;
for (auto const& i: keyManager.accountDetails())
{
auto b = c->balanceAt(i.first);
cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b;
}
cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
}
else if (c && cmd == "transact")
{
@ -1422,7 +1478,7 @@ int main(int argc, char** argv)
try
{
Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas);
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
@ -1491,7 +1547,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice);
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -1602,13 +1658,13 @@ int main(int argc, char** argv)
}
}
}
else if (cmd == "setsecret")
else if (cmd == "setsigningkey")
{
if (iss.peek() != -1)
{
string hexSec;
iss >> hexSec;
sigKey = KeyPair(h256(fromHex(hexSec)));
signingKey = Address(fromHex(hexSec));
}
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
@ -1625,7 +1681,7 @@ int main(int argc, char** argv)
{
try
{
coinbase = h160(fromHex(hexAddr, WhenError::Throw));
beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
@ -1648,7 +1704,7 @@ int main(int argc, char** argv)
string path;
iss >> path;
RLPStream config(2);
config << sigKey.secret() << coinbase;
config << signingKey << beneficiary;
writeFile(path, config.out());
}
else
@ -1664,8 +1720,8 @@ int main(int argc, char** argv)
if (b.size())
{
RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
}
else
cwarn << path << "has no content!";

13
libdevcore/StructuredLogger.cpp

@ -34,6 +34,15 @@ using namespace std;
namespace dev
{
void StructuredLogger::initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
if (_destinationURL.size() > 7 && _destinationURL.substr(0, 7) == "file://")
m_out.open(_destinationURL.substr(7));
// TODO: support tcp://
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{
Json::Value event;
@ -41,7 +50,7 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const&
Json::FastWriter fastWriter;
Guard l(s_lock);
event[_name] = _value;
cout << fastWriter.write(event) << endl;
(m_out.is_open() ? m_out : cout) << fastWriter.write(event) << endl;
}
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
@ -51,6 +60,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting");
@ -64,6 +74,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping");

14
libdevcore/StructuredLogger.h

@ -25,6 +25,7 @@
#pragma once
#include <fstream>
#include <string>
#include <chrono>
@ -46,11 +47,7 @@ public:
* http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps
*/
void initialize(bool _enabled, std::string const& _timeFormat)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
void initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL);
static StructuredLogger& get()
{
@ -92,6 +89,11 @@ public:
std::string const& _prevHash
);
static void transactionReceived(std::string const& _hash, std::string const& _remoteId);
// TODO: static void pendingQueueChanged(std::vector<h256> const& _hashes);
// TODO: static void miningStarted();
// TODO: static void stillMining(unsigned _hashrate);
// TODO: static void miningStopped();
private:
// Singleton class. Private default ctor and no copying
StructuredLogger() = default;
@ -102,6 +104,8 @@ private:
bool m_enabled = false;
std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S";
mutable std::ofstream m_out;
};
}

33
libethereum/BlockChain.cpp

@ -456,7 +456,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{
// Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it.
State s(_db); //, bi.coinbaseAddress
State s(_db);
auto tdIncrease = s.enactOn(&_block, bi, *this, _ir);
BlockLogBlooms blb;
@ -467,6 +467,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
br.receipts.push_back(s.receipt(i));
}
s.cleanup(true);
td = pd.totalDifficulty + tdIncrease;
#if ETH_TIMED_IMPORTS
@ -603,7 +604,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{
newLastBlockHash = bi.hash();
newLastBlockNumber = (unsigned)bi.number;
extrasBatch.Put(ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
@ -623,10 +623,31 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
try {
State canary(_db, *this, bi.hash());
}
catch (...)
{
clog(BlockChainDebug) << "Failed to initialise State object form imported block.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
if (m_lastBlockHash != newLastBlockHash)
DEV_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
}
#if ETH_PARANOIA || !ETH_TRUE
@ -646,14 +667,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
if (!route.empty())
noteCanonChanged();
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
h256s fresh;
h256s dead;
bool isOld = true;

2
libethereum/KeyManager.h

@ -66,6 +66,8 @@ public:
bool load(std::string const& _pass);
void save(std::string const& _pass) const { write(_pass, m_keysFile); }
void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; }
AddressHash accounts() const;
std::unordered_map<Address, std::pair<std::string, std::string>> accountDetails() const;

1
libethereum/State.cpp

@ -707,6 +707,7 @@ void State::cleanup(bool _fullCommit)
{
if (_fullCommit)
{
paranoia("immediately before database commit", true);
// Commit the new trie to disk.

2
libethereum/State.h

@ -49,7 +49,7 @@ class BlockChain;
class State;
struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 7; };
struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 5; };
struct StateDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct StateSafeExceptions: public LogChannel { static const char* name(); static const int verbosity = 21; };

Loading…
Cancel
Save