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(true);
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, ui->optimize->isChecked());
solidity = "Solidity
";
solidity += "var " + QString::fromStdString(compiler.defaultContractName()) + " = 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.
";
}
}
#ifndef _MSC_VER
else if (sourceIsSerpent(src))
{
try
{
m_data = dev::asBytes(::compile(src));
for (auto& i: errors)
i = "(LLL " + i + ")";
}
catch (string const& err)
{
errors.push_back("Serpent " + err);
}
}
#endif
else
{
m_data = compileLLL(src, ui->optimize->isChecked(), &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "Pre
" + QString::fromStdString(asmcode).toHtmlEscaped() + "
";
if (ui->optimize->isChecked())
{
asmcode = compileLLLToAsm(src, true);
lll = "Opt
" + QString::fromStdString(asmcode).toHtmlEscaped() + "
" + lll;
}
}
}
QString errs;
qint64 gasNeeded = 0;
if (errors.size())
{
errs = "Errors
";
for (auto const& i: errors)
errs.append("" + QString::fromStdString(i).toHtmlEscaped() + "
");
}
else
{
if (true)
{
auto s = findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
if (!s)
errs += "ERROR No single account contains enough gas.
";
// TODO: use account with most balance anyway.
else
{
ExecutionResult er = ethereum()->create(s, value(), m_data, ethereum()->gasLimitRemaining(), gasPrice());
gasNeeded = (qint64)er.gasUsed;
auto base = (qint64)Interface::txGas(m_data, 0);
errs += QString("INFO Gas required: %1 base, %2 init
").arg(base).arg((qint64)er.gasUsed - base);
if (er.excepted != TransactionException::None)
errs += "ERROR " + QString::fromStdString(toString(er.excepted)) + "
";
if (er.codeDeposit == CodeDeposit::Failed)
errs += "ERROR Code deposit failed due to insufficient gas
";
}
}
else
gasNeeded = (qint64)Interface::txGas(m_data, 0);
}
ui->code->setHtml(errs + lll + solidity + "Code
" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "Hex
" Div(Mono) + QString::fromStdString(toHex(m_data)) + "");
if (ui->gas->value() == ui->gas->minimum())
{
ui->gas->setMinimum(gasNeeded);
ui->gas->setValue(gasNeeded);
}
else
ui->gas->setMinimum(gasNeeded);
// if (!ui->gas->isEnabled())
// ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
// if (ui->gas->value() == ui->gas->minimum() && !src.empty())
// ui->gas->setValue((int)(m_ethereum->postState().gasLimitRemaining() / 10));
}
else
{
auto base = (qint64)Interface::txGas(m_data, 0);
m_data = parseData(ui->data->toPlainText().toStdString());
auto to = m_context->fromString(ui->destination->currentText());
QString natspec;
QString errs;
if (ethereum()->codeAt(to, PendingBlock).size())
{
string userNotice = m_natSpecDB->getUserNotice(ethereum()->postState().codeHash(to), m_data);
if (userNotice.empty())
natspec = "Destination contract unknown.";
else
{
NatspecExpressionEvaluator evaluator;
natspec = evaluator.evalExpression(QString::fromStdString(userNotice));
}
qint64 gasNeeded = 0;
if (true)
{
auto s = findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
if (!s)
errs += "ERROR No single account contains enough gas.
";
// TODO: use account with most balance anyway.
else
{
ExecutionResult er = ethereum()->call(s, value(), to, m_data, ethereum()->gasLimitRemaining(), gasPrice());
gasNeeded = (qint64)er.gasUsed;
errs += QString("INFO Gas required: %1 base, %2 exec
").arg(base).arg((qint64)er.gasUsed - base);
if (er.excepted != TransactionException::None)
errs += "ERROR " + QString::fromStdString(toString(er.excepted)) + "
";
}
}
else
gasNeeded = (qint64)Interface::txGas(m_data, 0);
if (ui->gas->value() == ui->gas->minimum())
{
ui->gas->setMinimum(gasNeeded);
ui->gas->setValue(gasNeeded);
}
else
ui->gas->setMinimum(gasNeeded);
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
natspec += "Destination not a contract.";
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setMinimum(base);
ui->gas->setValue(base);
ui->gas->setEnabled(false);
}
ui->code->setHtml(errs + "NatSpec
" + natspec + "Dump
" + QString::fromStdString(dev::memDump(m_data, 8, true)) + "Hex
" + Div(Mono) + QString::fromStdString(toHex(m_data)) + "");
}
updateFee();
}
Secret Transact::findSecret(u256 _totalReq) const
{
if (ethereum())
for (auto const& i: m_myKeys)
if (ethereum()->balanceAt(i.address(), PendingBlock) >= _totalReq)
return i.secret();
return Secret();
}
void Transact::on_send_clicked()
{
Secret s = findSecret(value() + fee());
if (!s)
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
return;
}
if (isCreation())
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler(true);
m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natSpecDB->add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser));
}
}
catch (...)
{
}
}
else
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
close();
}
void Transact::on_debug_clicked()
{
try
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
State st(ethereum()->postState());
Secret s = i.secret();
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t);
dw.exec();
return;
}
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
}
catch (dev::Exception const& _e)
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction. Low-level error: " + QString::fromStdString(diagnostic_information(_e)));
// this output is aimed at developers, reconsider using _e.what for more user friendly output.
}
}