() == 0)
s << "Sealing client: " << htmlEscaped(r[1].toString()) << "" << "
";
}
catch (...) {}
s << "D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
";
s << " Children: " << details.children.size() << "";
s << "Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
";
s << "Beneficiary: " << htmlEscaped(pretty(info.beneficiary())) << " " << info.beneficiary() << "" << "
";
s << "Seed hash: " << info.seedHash() << "" << "
";
s << "Mix hash: " << info.mixHash() << "" << "
";
s << "Nonce: " << info.nonce() << "" << "
";
s << "Hash w/o nonce: " << info.hashWithout() << "" << "
";
s << "Difficulty: " << info.difficulty() << "" << "
";
if (info.number())
{
auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce());
s << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
";
s << "Parent: " << info.parentHash() << "" << "
";
}
else
{
s << "Proof-of-Work: Phil has nothing to prove
";
s << "Parent: It was a virgin birth
";
}
// s << "Bloom:
" << details.bloom << "";
s << "
State root: " << ETH_HTML_SPAN(ETH_HTML_MONO) << info.stateRoot().hex() << "
";
s << "
Extra data: " << ETH_HTML_SPAN(ETH_HTML_MONO) << toHex(info.extraData()) << "
";
if (!!info.logBloom())
s << "
Log Bloom: " << info.logBloom() << "
";
else
s << "
Log Bloom: Uneventful
";
s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
";
s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
";
for (auto u: block[2])
{
Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData);
char const* line = "
";
s << line << "Hash: " << uncle.hash() << "" << "
";
s << line << "Parent:
" << uncle.parentHash() << "" << "
";
s << line << "Number: " << uncle.number() << "" << "";
s << line << "Coinbase: " << htmlEscaped(pretty(uncle.beneficiary())) << " " << uncle.beneficiary() << "" << "";
s << line << "Seed hash: " << uncle.seedHash() << "" << "";
s << line << "Mix hash: " << uncle.mixHash() << "" << "";
s << line << "Nonce: " << uncle.nonce() << "" << "";
s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << "";
s << line << "Difficulty: " << uncle.difficulty() << "" << "";
auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce());
s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "";
}
if (info.parentHash())
s << "Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
";
else
s << "Pre: Nothing is before Phil" << "
";
s << "Receipts: @" << info.receiptsRoot() << ":" << "
";
BlockReceipts receipts = ethereum()->blockChain().receipts(h);
unsigned ii = 0;
for (auto const& i: block[1])
{
s << "" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
";
++ii;
}
s << "Post: " << info.stateRoot() << "" << "
";
s << "Dump: " ETH_HTML_SPAN(ETH_HTML_MONO) << toHex(block[0].data()) << "" << "
";
s << "Receipts-Hex: " ETH_HTML_SPAN(ETH_HTML_MONO) << toHex(receipts.rlp()) << "
";
}
else
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
Transaction tx(block[1][txi].data(), CheckTransaction::Everything);
auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce()));
TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi];
s << "" << th << "
";
s << "" << h << "[" << txi << "]
";
s << "From: " << htmlEscaped(pretty(ss)) << " " << ss << "" << "
";
if (tx.isCreation())
s << "Creates: " << htmlEscaped(pretty(right160(th))) << " " << right160(th) << "
";
else
s << "To: " << htmlEscaped(pretty(tx.receiveAddress())) << " " << tx.receiveAddress() << "
";
s << "Value: " << formatBalance(tx.value()) << "" << "
";
s << " #" << tx.nonce() << "" << "";
s << "Gas price: " << formatBalance(tx.gasPrice()) << "" << "
";
s << "Gas: " << tx.gas() << "" << "
";
s << "V: " << hex << nouppercase << (int)tx.signature().v << " + 27" << "
";
s << "R: " << hex << nouppercase << tx.signature().r << "" << "
";
s << "S: " << hex << nouppercase << tx.signature().s << "" << "
";
s << "Msg: " << tx.sha3(eth::WithoutSignature) << "" << "
";
if (!tx.data().empty())
{
if (tx.isCreation())
s << "Code
" << disassemble(tx.data());
else
s << "Data
" << dev::memDump(tx.data(), 16, true);
}
s << "Hex: " ETH_HTML_SPAN(ETH_HTML_MONO) << toHex(block[1][txi].data()) << "
";
s << "
";
if (!!receipt.bloom())
s << "Log Bloom: " << receipt.bloom() << "
";
else
s << "Log Bloom: Uneventful
";
s << "Gas Used: " << receipt.gasUsed() << "
";
s << "End State: " << receipt.stateRoot().abridged() << "
";
auto r = receipt.rlp();
s << "Receipt: " << toString(RLP(r)) << "
";
s << "Receipt-Hex: " ETH_HTML_SPAN(ETH_HTML_MONO) << toHex(receipt.rlp()) << "
";
s << "Diff
" << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true);
}
ui->info->appendHtml(QString::fromStdString(s.str()));
ui->info->moveCursor(QTextCursor::Start);
}
}
void Main::on_debugCurrent_triggered()
{
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
if (!item->data(Qt::UserRole + 1).isNull())
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
bytes t = ethereum()->blockChain().transaction(h, txi);
State s(ethereum()->state(txi, h));
BlockInfo bi(ethereum()->blockChain().info(h));
Executive e(s, ethereum()->blockChain(), EnvInfo(bi));
Debugger dw(this, this);
dw.populate(e, Transaction(t, CheckTransaction::Everything));
dw.exec();
}
}
}
std::string minHex(h256 const& _h)
{
unsigned i = 0;
for (; i < 31 && !_h[i]; ++i) {}
return toHex(_h.ref().cropped(i));
}
void Main::on_dumpBlockState_triggered()
{
#if ETH_FATDB || !ETH_TRUE
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
QString fn = QFileDialog::getSaveFileName(this, "Select file to output state dump");
ofstream f(fn.toStdString());
if (f.is_open())
{
f << "{" << endl;
// js::mObject s;
State state = ethereum()->block(h).state();
int fi = 0;
for (pair const& i: state.addresses())
{
f << (fi++ ? "," : "") << "\"" << i.first.hex() << "\": { ";
f << "\"balance\": \"" << toString(i.second) << "\", ";
if (state.codeHash(i.first) != EmptySHA3)
{
f << "\"codeHash\": \"" << state.codeHash(i.first).hex() << "\", ";
f << "\"storage\": {";
int fj = 0;
for (pair const& j: state.storage(i.first))
f << (fj++ ? "," : "") << "\"" << minHex(j.first) << "\":\"" << minHex(j.second) << "\"";
f << "}, ";
}
f << "\"nonce\": \"" << toString(state.transactionsFrom(i.first)) << "\"";
f << "}" << endl; // end account
if (!(fi % 100))
f << flush;
}
f << "}";
}
}
#endif
}
void Main::debugDumpState(int _add)
{
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
if (!item->data(Qt::UserRole + 1).isNull())
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output state dump");
ofstream f(fn.toStdString());
if (f.is_open())
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
f << ethereum()->state(txi + _add, h) << endl;
}
}
}
}
void Main::on_idealPeers_valueChanged(int)
{
m_webThree->setIdealPeerCount(ui->idealPeers->value());
}
void Main::on_ourAccounts_doubleClicked()
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
/*void Main::on_log_doubleClicked()
{
ui->log->setPlainText("");
m_logHistory.clear();
}*/
static shh::Topics topicFromText(QString _s)
{
shh::BuildTopic ret;
while (_s.size())
{
QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?");
QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?");
QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?");
bytes part;
if (r.exactMatch(_s))
{
for (auto i: r.cap(2))
part.push_back((byte)i.toLatin1());
if (r.cap(1) != "$")
for (int i = r.cap(2).size(); i < 32; ++i)
part.push_back(0);
else
part.push_back(0);
_s = r.cap(3);
}
else if (d.exactMatch(_s))
{
u256 v(d.cap(2).toStdString());
if (d.cap(6) == "szabo")
v *= szabo;
else if (d.cap(5) == "finney")
v *= finney;
else if (d.cap(4) == "ether")
v *= ether;
bytes bs = dev::toCompactBigEndian(v);
if (d.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
part.push_back(0);
for (auto b: bs)
part.push_back(b);
_s = d.cap(7);
}
else if (h.exactMatch(_s))
{
bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString());
if (h.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
part.push_back(0);
for (auto b: bs)
part.push_back(b);
_s = h.cap(5);
}
else
_s = _s.mid(1);
ret.shift(part);
}
return ret;
}
void Main::on_clearPending_triggered()
{
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
ethereum()->clearPending();
readSettings(true);
installWatches();
refreshAll();
}
void Main::on_retryUnknown_triggered()
{
ethereum()->retryUnknown();
}
void Main::on_killBlockchain_triggered()
{
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
ethereum()->killChain();
readSettings(true);
installWatches();
refreshAll();
}
void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
ui->clientName->setEnabled(!ui->net->isChecked());
web3()->setClientVersion(WebThreeDirect::composeClientVersion("AlethZero", ui->clientName->text().toStdString()));
if (ui->net->isChecked())
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId((h256)(u256)(int)c_network);
web3()->startNetwork();
ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode()));
}
else
{
ui->downloadView->setEthereum(nullptr);
writeSettings();
web3()->stopNetwork();
}
}
void Main::on_connect_triggered()
{
if (!ui->net->isChecked())
{
ui->net->setChecked(true);
on_net_triggered();
}
m_connect.setEnvironment(m_servers);
if (m_connect.exec() == QDialog::Accepted)
{
bool required = m_connect.required();
string host(m_connect.host().toStdString());
NodeId nodeID;
try
{
nodeID = NodeId(fromHex(m_connect.nodeId().toStdString()));
}
catch (BadHexCharacter&) {}
m_connect.reset();
if (required)
web3()->requirePeer(nodeID, host);
else
web3()->addNode(nodeID, host);
}
}
void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
// EthashAux::computeFull(ethereum()->blockChain().number());
ethereum()->setBeneficiary(m_beneficiary);
ethereum()->startMining();
}
else
ethereum()->stopMining();
}
void Main::keysChanged()
{
onBalancesChange();
}
bool beginsWith(Address _a, bytes const& _b)
{
for (unsigned i = 0; i < min(20, _b.size()); ++i)
if (_a[i] != _b[i])
return false;
return true;
}
void Main::on_newAccount_triggered()
{
bool ok = true;
enum { NoVanity = 0, DirectICAP, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
QStringList items = {"No vanity (instant)", "Direct ICAP address", "Two pairs first (a few seconds)", "Two pairs first and second (a few minutes)", "Three pairs first (a few minutes)", "Four pairs first (several hours)", "Specific hex string"};
unsigned v = items.QList::indexOf(QInputDialog::getItem(this, "Vanity Key?", "Would you a vanity key? This could take several hours.", items, 1, false, &ok));
if (!ok)
return;
bytes bs;
if (v == StringMatch)
{
QString s = QInputDialog::getText(this, "Vanity Beginning?", "Enter some hex digits that it should begin with.\nNOTE: The more you enter, the longer generation will take.", QLineEdit::Normal, QString(), &ok);
if (!ok)
return;
bs = fromHex(s.toStdString());
}
KeyPair p;
bool keepGoing = true;
unsigned done = 0;
function f = [&]() {
KeyPair lp;
while (keepGoing)
{
done++;
if (done % 1000 == 0)
cnote << "Tried" << done << "keys";
lp = KeyPair::create();
auto a = lp.address();
if (v == NoVanity ||
(v == DirectICAP && !a[0]) ||
(v == FirstTwo && a[0] == a[1]) ||
(v == FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
(v == FirstThree && a[0] == a[1] && a[1] == a[2]) ||
(v == FirstFour && a[0] == a[1] && a[1] == a[2] && a[2] == a[3]) ||
(v == StringMatch && beginsWith(lp.address(), bs))
)
break;
}
if (keepGoing)
p = lp;
keepGoing = false;
};
vector ts;
for (unsigned t = 0; t < std::thread::hardware_concurrency() - 1; ++t)
ts.push_back(new std::thread(f));
f();
for (std::thread* t: ts)
{
t->join();
delete t;
}
QString s = QInputDialog::getText(this, "Create Account", "Enter this account's name");
if (QMessageBox::question(this, "Create Account", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
bool ok = false;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok);
if (!ok)
return;
m_keyManager.import(p.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(p.secret(), s.toStdString());
keysChanged();
}
void Main::on_killAccount_triggered()
{
if (ui->ourAccounts->currentRow() >= 0)
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + m_keyManager.accountName(h) + "?!"),
QString::fromStdString("Account " + m_keyManager.accountName(h) + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n"
"Are you sure you want to continue? \r\n If so, type 'YES' to confirm."),
QLineEdit::Normal, "NO");
if (s != "YES")
return;
m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
m_beneficiary = m_keyManager.accounts().front();
keysChanged();
if (m_beneficiary == h)
setBeneficiary(m_keyManager.accounts().front());
}
}
void Main::on_reencryptKey_triggered()
{
if (ui->ourAccounts->currentRow() >= 0)
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address a((byte const*)hba.data(), Address::ConstructFromPointer);
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = true;
KDF kdf = (KDF)kdfs.indexOf(QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs, kdfs.size() - 1, false, &ok));
if (!ok)
return;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!\nEnter nothing to use your Master password.", &hint, &ok);
if (!ok)
return;
try {
auto pw = [&](){
auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.passwordHint(a)), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw PasswordUnknown();
return p;
};
while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
catch (PasswordUnknown&) {}
}
}
void Main::on_reencryptAll_triggered()
{
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = false;
QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your keys:", kdfs, kdfs.size() - 1, false, &ok);
if (!ok)
return;
try {
for (Address const& a: m_keyManager.accounts())
while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){
auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.passwordHint(a))), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw PasswordUnknown();
return p;
}, (KDF)kdfs.indexOf(kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
catch (PasswordUnknown&) {}
}
void Main::on_go_triggered()
{
if (!ui->net->isChecked())
{
ui->net->setChecked(true);
on_net_triggered();
}
for (auto const& i: Host::pocHosts())
web3()->requirePeer(i.first, i.second);
}
std::string Main::prettyU256(dev::u256 const& _n) const
{
unsigned inc = 0;
string raw;
ostringstream s;
if (_n > szabo && _n < 1000000 * ether)
s << "" << formatBalance(_n) << " (0x" << hex << (uint64_t)_n << ")";
else if (!(_n >> 64))
s << "" << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << "" << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);
string n = pretty(a);
if (n.empty())
s << "0x" << a << "";
else
s << "" << htmlEscaped(n) << " (0x" << a.abridged() << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + htmlEscaped(raw) + "\"" + (inc ? " + " + toString(inc) : "") + "";
else
s << "0x" << (h256)_n << "";
return s.str();
}
void Main::on_post_clicked()
{
return;
shh::Message m;
m.setTo(stringToPublic(ui->shhTo->currentText()));
m.setPayload(parseData(ui->shhData->toPlainText().toStdString()));
Public f = stringToPublic(ui->shhFrom->currentText());
Secret from;
if (m_server->ids().count(f))
from = m_server->ids().at(f);
whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value()));
}
int Main::authenticate(QString _title, QString _text)
{
QMessageBox userInput(this);
userInput.setText(_title);
userInput.setInformativeText(_text);
userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
userInput.button(QMessageBox::Ok)->setText("Allow");
userInput.button(QMessageBox::Cancel)->setText("Reject");
userInput.setDefaultButton(QMessageBox::Cancel);
return userInput.exec();
}
void Main::refreshWhispers()
{
return;
ui->whispers->clear();
for (auto const& w: whisper()->all())
{
shh::Envelope const& e = w.second;
shh::Message m;
for (pair const& i: m_server->ids())
if (!!(m = e.open(shh::Topics(), i.second)))
break;
if (!m)
m = e.open(shh::Topics());
QString msg;
if (m.from())
// Good message.
msg = QString("{%1 -> %2} %3").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str());
else if (m)
// Maybe message.
msg = QString("{%1 -> %2} %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str());
time_t ex = e.expiry();
QString t(ctime(&ex));
t.chop(1);
QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg);
ui->whispers->addItem(item);
}
}
void Main::dappLoaded(Dapp& _dapp)
{
QUrl url = m_dappHost->hostDapp(std::move(_dapp));
ui->webView->page()->setUrl(url);
}
void Main::pageLoaded(QByteArray const& _content, QString const& _mimeType, QUrl const& _uri)
{
ui->webView->page()->setContent(_content, _mimeType, _uri);
}
void Main::initPlugin(Plugin* _p)
{
QSettings s("ethereum", "alethzero");
_p->readSettings(s);
}
void Main::finalisePlugin(Plugin* _p)
{
QSettings s("ethereum", "alethzero");
_p->writeSettings(s);
}
void Main::unloadPlugin(string const& _name)
{
shared_ptr p = takePlugin(_name);
if (p)
finalisePlugin(p.get());
}