errors;
QString lll;
QString solidity;
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0)
{
m_data = fromHex(src);
}
else if (sourceIsSolidity(src))
{
dev::solidity::CompilerStack compiler;
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, m_enableOptimizer);
solidity = "Solidity
";
solidity += "var " + QString::fromStdString(compiler.getContractNames().front()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");
";
solidity += "" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
";
solidity += "" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "
";
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "Solidity
" + QString::fromStdString(error.str()).toHtmlEscaped() + "
";
}
catch (...)
{
solidity = "Solidity
Uncaught exception.
";
}
}
else if (sourceIsSerpent(src))
{
try
{
m_data = dev::asBytes(::compile(src));
for (auto& i: errors)
i = "(LLL " + i + ")";
}
catch (string err)
{
errors.push_back("Serpent " + err);
}
}
else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "Pre
" + QString::fromStdString(asmcode).toHtmlEscaped() + "
";
if (m_enableOptimizer)
{
asmcode = compileLLLToAsm(src, true);
lll = "Opt
" + QString::fromStdString(asmcode).toHtmlEscaped() + "
" + lll;
}
}
}
QString errs;
if (errors.size())
{
errs = "Errors
";
for (auto const& i: errors)
errs.append("" + QString::fromStdString(i).toHtmlEscaped() + "
");
}
ui->code->setHtml(errs + lll + solidity + "Code
" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "Hex
" Div(Mono) + QString::fromStdString(toHex(m_data)) + "");
ui->gas->setMinimum((qint64)Client::txGas(m_data, 0));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
m_data = parseData(ui->data->toPlainText().toStdString());
ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true)));
if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size())
{
ui->gas->setMinimum((qint64)Client::txGas(m_data, 1));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)Client::txGas(m_data));
ui->gas->setEnabled(false);
}
}
updateFee();
}
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_killBlockchain_triggered()
{
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
ethereum()->killChain();
readSettings(true);
installWatches();
refreshAll();
}
bool Main::isCreation() const
{
return ui->destination->currentText().isEmpty() || ui->destination->currentText() == "(Create Contract)";
}
u256 Main::fee() const
{
return ui->gas->value() * gasPrice();
}
u256 Main::value() const
{
if (ui->valueUnits->currentIndex() == -1)
return 0;
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
}
u256 Main::gasPrice() const
{
if (ui->gasPriceUnits->currentIndex() == -1)
return 0;
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first;
}
u256 Main::total() const
{
return value() + fee();
}
void Main::updateFee()
{
ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false;
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
ok = true;
break;
}
ui->send->setEnabled(ok);
QPalette p = ui->total->palette();
p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00));
ui->total->setPalette(p);
}
void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
ui->clientName->setEnabled(!ui->net->isChecked());
string n = string("AlethZero/v") + dev::Version;
if (ui->clientName->text().size())
n += "/" + ui->clientName->text().toStdString();
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);
web3()->setClientVersion(n);
if (ui->net->isChecked())
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
if (m_peers.size()/* && ui->usePast->isChecked()*/)
web3()->restoreNodes(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
}
else
{
ui->downloadView->setDownloadMan(nullptr);
web3()->stopNetwork();
}
}
void Main::on_connect_triggered()
{
if (!ui->net->isChecked())
{
ui->net->setChecked(true);
on_net_triggered();
}
bool ok = false;
QString s = QInputDialog::getItem(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", m_servers, m_servers.count() ? rand() % m_servers.count() : 0, true, &ok);
if (ok && s.contains(":"))
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
web3()->connect(host, port);
}
}
void Main::on_verbosity_valueChanged()
{
g_logVerbosity = ui->verbosity->value();
ui->verbosityLabel->setText(QString::number(g_logVerbosity));
}
void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
ethereum()->setAddress(m_myKeys.last().address());
ethereum()->startMining();
}
else
ethereum()->stopMining();
}
void Main::on_send_clicked()
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{
debugFinished();
Secret s = i.secret();
if (isCreation())
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler;
m_data = compiler.compile(src, m_enableOptimizer);
for (string& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natspecDB.add(contractHash,
compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER));
}
}
catch (...)
{
statusBar()->showMessage("Couldn't compile Solidity Contract.");
}
}
else
ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return;
}
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
void Main::keysChanged()
{
onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
}
void Main::on_debug_clicked()
{
debugFinished();
try
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
Secret s = i.secret();
m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s);
auto r = t.rlp();
populateDebugger(&r);
m_currentExecution.reset();
return;
}
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
catch (dev::Exception const& _e)
{
statusBar()->showMessage("Error running transaction: " + QString::fromStdString(diagnostic_information(_e)));
// this output is aimed at developers, reconsider using _e.what for more user friendly output.
}
}
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_create_triggered()
{
bool ok = true;
enum { NoVanity = 0, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
QStringList items = {"No vanity (instant)", "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, 0, 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 == 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;
}
m_myKeys.append(p);
keysChanged();
}
void Main::on_killAccount_triggered()
{
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size())
{
auto k = m_myKeys[ui->ourAccounts->currentRow()];
if (ethereum()->balanceAt(k.address()) != 0 && QMessageBox::critical(this, "Kill Account?!", "Account " + render(k.address()) + " has " + QString::fromStdString(formatBalance(ethereum()->balanceAt(k.address()))) + " in it. It, 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.\nAre you sure you want to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow());
keysChanged();
}
}
void Main::on_debugStep_triggered()
{
if (ui->debugTimeline->value() < m_history.size()) {
auto l = m_history[ui->debugTimeline->value()].levels.size();
if ((ui->debugTimeline->value() + 1) < m_history.size() && m_history[ui->debugTimeline->value() + 1].levels.size() > l)
{
on_debugStepInto_triggered();
if (m_history[ui->debugTimeline->value()].levels.size() > l)
on_debugStepOut_triggered();
}
else
on_debugStepInto_triggered();
}
}
void Main::on_debugStepInto_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() + 1);
ui->callStack->setCurrentRow(0);
}
void Main::on_debugStepOut_triggered()
{
if (ui->debugTimeline->value() < m_history.size())
{
auto ls = m_history[ui->debugTimeline->value()].levels.size();
auto l = ui->debugTimeline->value();
for (; l < m_history.size() && m_history[l].levels.size() >= ls; ++l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Main::on_debugStepBackInto_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() - 1);
ui->callStack->setCurrentRow(0);
}
void Main::on_debugStepBack_triggered()
{
auto l = m_history[ui->debugTimeline->value()].levels.size();
if (ui->debugTimeline->value() > 0 && m_history[ui->debugTimeline->value() - 1].levels.size() > l)
{
on_debugStepBackInto_triggered();
if (m_history[ui->debugTimeline->value()].levels.size() > l)
on_debugStepBackOut_triggered();
}
else
on_debugStepBackInto_triggered();
}
void Main::on_debugStepBackOut_triggered()
{
if (ui->debugTimeline->value() > 0 && m_history.size() > 0)
{
auto ls = m_history[min(ui->debugTimeline->value(), m_history.size() - 1)].levels.size();
int l = ui->debugTimeline->value();
for (; l > 0 && m_history[l].levels.size() >= ls; --l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Main::on_dumpTrace_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
void Main::on_dumpTracePretty_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
{
f << endl << " STACK" << endl;
for (auto i: ws.stack)
f << (h256)i << endl;
f << " MEMORY" << endl << dev::memDump(ws.memory);
f << " STORAGE" << endl;
for (auto const& i: ws.storage)
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ws.levels.size() << " | " << ws.cur << " | #" << ws.steps << " | " << hex << setw(4) << setfill('0') << ws.curPC << " : " << instructionInfo(ws.inst).name << " | " << dec << ws.gas << " | -" << dec << ws.gasCost << " | " << ws.newMemSize << "x32";
}
}
void Main::on_dumpTraceStorage_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
{
if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE)
for (auto i: ws.storage)
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
}
void Main::on_go_triggered()
{
if (!ui->net->isChecked())
{
ui->net->setChecked(true);
on_net_triggered();
}
web3()->connect(Host::pocHost());
}
void Main::on_callStack_currentItemChanged()
{
updateDebugger();
}
void Main::alterDebugStateGroup(bool _enable) const
{
ui->debugStep->setEnabled(_enable);
ui->debugStepInto->setEnabled(_enable);
ui->debugStepOut->setEnabled(_enable);
ui->debugStepBackInto->setEnabled(_enable);
ui->debugStepBackOut->setEnabled(_enable);
ui->dumpTrace->setEnabled(_enable);
ui->dumpTraceStorage->setEnabled(_enable);
ui->dumpTracePretty->setEnabled(_enable);
ui->debugStepBack->setEnabled(_enable);
ui->debugPanel->setEnabled(_enable);
}
void Main::debugFinished()
{
m_codes.clear();
m_pcWarp.clear();
m_history.clear();
m_lastLevels.clear();
m_lastCode = h256();
ui->callStack->clear();
ui->debugCode->clear();
ui->debugStack->clear();
ui->debugMemory->setHtml("");
ui->debugStorage->setHtml("");
ui->debugStateInfo->setText("");
alterDebugStateGroup(false);
// ui->send->setEnabled(true);
}
void Main::initDebugger()
{
// ui->send->setEnabled(false);
if (m_history.size())
{
alterDebugStateGroup(true);
ui->debugCode->setEnabled(false);
ui->debugTimeline->setMinimum(0);
ui->debugTimeline->setMaximum(m_history.size());
ui->debugTimeline->setValue(0);
}
}
void Main::on_debugTimeline_valueChanged()
{
updateDebugger();
}
QString Main::prettyU256(dev::u256 _n) const
{
unsigned inc = 0;
QString 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);
QString n = pretty(a);
if (n.isNull())
s << "0x" << a << "";
else
s << "" << n.toHtmlEscaped().toStdString() << " (0x" << a.abridged() << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + raw.toHtmlEscaped() + "\"" + (inc ? " + " + QString::number(inc) : "") + "";
else
s << "0x" << (h256)_n << "";
return QString::fromStdString(s.str());
}
void Main::updateDebugger()
{
if (m_history.size())
{
WorldState const& nws = m_history[min((int)m_history.size() - 1, ui->debugTimeline->value())];
WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws;
if (ui->debugTimeline->value() >= m_history.size())
{
if (ws.gasCost > ws.gas)
ui->debugMemory->setHtml("OUT-OF-GAS
");
else if (ws.inst == Instruction::RETURN && ws.stack.size() >= 2)
{
unsigned from = (unsigned)ws.stack.back();
unsigned size = (unsigned)ws.stack[ws.stack.size() - 2];
unsigned o = 0;
bytes out(size, 0);
for (; o < size && from + o < ws.memory.size(); ++o)
out[o] = ws.memory[from + o];
ui->debugMemory->setHtml("RETURN
" + QString::fromStdString(dev::memDump(out, 16, true)));
}
else if (ws.inst == Instruction::STOP)
ui->debugMemory->setHtml("STOP
");
else if (ws.inst == Instruction::SUICIDE && ws.stack.size() >= 1)
ui->debugMemory->setHtml("SUICIDE
0x" + QString::fromStdString(toString(right160(ws.stack.back()))));
else
ui->debugMemory->setHtml("EXCEPTION
");
ostringstream ss;
ss << dec << "EXIT | GAS: " << dec << max(0, (dev::bigint)ws.gas - ws.gasCost);
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
ui->debugStorage->setHtml("");
ui->debugCallData->setHtml("");
m_lastData = h256();
ui->callStack->clear();
m_lastLevels.clear();
ui->debugCode->clear();
m_lastCode = h256();
ui->debugStack->setHtml("");
}
else
{
if (m_lastLevels != nws.levels || !ui->callStack->count())
{
m_lastLevels = nws.levels;
ui->callStack->clear();
for (unsigned i = 0; i <= nws.levels.size(); ++i)
{
WorldState const& s = i ? *nws.levels[nws.levels.size() - i] : nws;
ostringstream out;
out << s.cur.abridged();
if (i)
out << " " << instructionInfo(s.inst).name << " @0x" << hex << s.curPC;
ui->callStack->addItem(QString::fromStdString(out.str()));
}
}
if (ws.code != m_lastCode)
{
bytes const& code = m_codes[ws.code];
QListWidget* dc = ui->debugCode;
dc->clear();
m_pcWarp.clear();
for (unsigned i = 0; i <= code.size(); ++i)
{
byte b = i < code.size() ? code[i] : 0;
try
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
ostringstream out;
out << hex << setw(4) << setfill('0') << i;
m_pcWarp[i] = dc->count();
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc)));
i += bc;
}
dc->addItem(QString::fromStdString(out.str()) + " " + s);
}
catch (...)
{
cerr << "Unhandled exception!" << endl <<
boost::current_exception_diagnostic_information();
break; // probably hit data segment
}
}
m_lastCode = ws.code;
}
if (ws.callData != m_lastData)
{
m_lastData = ws.callData;
if (ws.callData)
{
assert(m_codes.count(ws.callData));
ui->debugCallData->setHtml(QString::fromStdString(dev::memDump(m_codes[ws.callData], 16, true)));
}
else
ui->debugCallData->setHtml("");
}
QString stack;
for (auto i: ws.stack)
stack.prepend("" + prettyU256(i) + "
");
ui->debugStack->setHtml(stack);
ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true)));
assert(m_codes.count(ws.code));
if (m_codes[ws.code].size() >= (unsigned)ws.curPC)
{
int l = m_pcWarp[(unsigned)ws.curPC];
ui->debugCode->setCurrentRow(max(0, l - 5));
ui->debugCode->setCurrentRow(min(ui->debugCode->count() - 1, l + 5));
ui->debugCode->setCurrentRow(l);
}
else
cwarn << "PC (" << (unsigned)ws.curPC << ") is after code range (" << m_codes[ws.code].size() << ")";
ostringstream ss;
ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << instructionInfo(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas;
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s;
for (auto const& i: ws.storage)
s << "@" << prettyU256(i.first).toStdString() << " " << prettyU256(i.second).toStdString() << "
";
ui->debugStorage->setHtml(QString::fromStdString(s.str()));
}
}
}
void Main::on_post_clicked()
{
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()));
}
string Main::lookupNatSpec(dev::h256 const& _contractHash) const
{
return m_natspecDB.retrieve(_contractHash);
}
string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)
{
return m_natspecDB.getUserNotice(_contractHash, _transactionData);
}
void Main::refreshWhispers()
{
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(i.second)))
break;
if (!m)
m = e.open();
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.topics()).c_str()).arg(msg);
ui->whispers->addItem(item);
}
}