p;
+ if (!isCreation())
+ {
+ if (!ui->destination->currentData().isNull() && ui->destination->currentText() == ui->destination->itemText(ui->destination->currentIndex()))
+ p.first = Address(ui->destination->currentData().toString().trimmed().toStdString());
+ else
+ p = m_main->fromString(ui->destination->currentText().trimmed().toStdString());
+ }
+ return p;
+}
+
+void Transact::timerEvent(QTimerEvent*)
+{
+ Address from = fromAccount();
+ Address to = toAccount().first;
+
+ if (m_upperBound != m_lowerBound)
+ {
+ qint64 mid = (m_lowerBound + m_upperBound) / 2;
+ ExecutionResult er;
+ if (isCreation())
+ er = ethereum()->create(from, value(), m_data, mid, gasPrice(), PendingBlock, FudgeFactor::Lenient);
+ else
+ er = ethereum()->call(from, value(), to, m_data, mid, gasPrice(), PendingBlock, FudgeFactor::Lenient);
+ if (er.excepted == TransactionException::OutOfGas || er.excepted == TransactionException::OutOfGasBase || er.excepted == TransactionException::OutOfGasIntrinsic || er.codeDeposit == CodeDeposit::Failed)
+ m_lowerBound = m_lowerBound == mid ? m_upperBound : mid;
+ else
+ {
+ m_lastGood = er;
+ m_upperBound = m_upperBound == mid ? m_lowerBound : mid;
+ }
+
+ updateBounds();
+ if (m_lowerBound == m_upperBound)
+ finaliseBounds();
+ }
+}
+
+void Transact::updateBounds()
{
- return isCreation() ? Address() : m_main->fromString(ui->destination->currentText().toStdString()).first;
+ ui->minGas->setValue(m_lowerBound);
+ ui->maxGas->setValue(m_upperBound);
+ double oran = m_startUpperBound - m_startLowerBound;
+ double nran = m_upperBound - m_lowerBound;
+ int x = int(log2(oran / nran) * 100.0 / log2(oran * 2));
+ ui->progressGas->setValue(x);
+ ui->progressGas->setVisible(true);
+ ui->gas->setSpecialValueText(QString("Auto (%1 gas)").arg(m_upperBound));
+}
+
+void Transact::finaliseBounds()
+{
+ quint64 baseGas = (quint64)Transaction::gasRequired(m_data, 0);
+ ui->progressGas->setVisible(false);
+
+ quint64 executionGas = m_upperBound - baseGas;
+ QString htmlInfo = QString("INFO Gas required: %1 total = %2 base, %3 exec [%4 refunded later]
").arg(m_upperBound).arg(baseGas).arg(executionGas).arg((qint64)m_lastGood.gasRefunded);
+
+ auto bail = [&](QString he) {
+ ui->send->setEnabled(false);
+ ui->code->setHtml(he + htmlInfo + m_dataInfo);
+ };
+
+ auto s = fromAccount();
+ auto b = ethereum()->balanceAt(s, PendingBlock);
+
+ if (b < value() + baseGas * gasPrice())
+ {
+ // Not enough - bail.
+ bail("ERROR Account doesn't contain enough for paying even the basic amount of gas required.
");
+ return;
+ }
+ if (m_upperBound > m_ethereum->gasLimitRemaining())
+ {
+ // Not enough - bail.
+ bail("ERROR Gas remaining in block isn't enough to allow the gas required.
");
+ return;
+ }
+ if (m_lastGood.excepted != TransactionException::None)
+ {
+ bail("ERROR " + QString::fromStdString(toString(m_lastGood.excepted)) + "
");
+ return;
+ }
+ if (m_lastGood.codeDeposit == CodeDeposit::Failed)
+ {
+ bail("ERROR Code deposit failed due to insufficient gas; " + QString::fromStdString(toString(m_lastGood.gasForDeposit)) + " GAS < " + QString::fromStdString(toString(m_lastGood.depositSize)) + " bytes * " + QString::fromStdString(toString(c_createDataGas)) + "GAS/byte
");
+ return;
+ }
+
+ updateFee();
+ ui->code->setHtml(htmlInfo + m_dataInfo);
+ ui->send->setEnabled(true);
+ killTimer(m_gasCalcTimer);
}
GasRequirements Transact::determineGasRequirements()
@@ -342,39 +429,36 @@ GasRequirements Transact::determineGasRequirements()
qint64 baseGas = (qint64)Transaction::gasRequired(m_data, 0);
Address from = fromAccount();
- Address to = toAccount();
+ Address to = toAccount().first;
ExecutionResult lastGood;
- bool haveUpperBound = false;
- qint64 lowerBound = baseGas;
- qint64 upperBound = (qint64)ethereum()->gasLimitRemaining();
- for (unsigned i = 0; i < 20 && ((haveUpperBound && upperBound - lowerBound > 100) || !haveUpperBound); ++i) // get to with 100.
+ m_startLowerBound = baseGas;
+ m_startUpperBound = (qint64)ethereum()->gasLimitRemaining();
+ for (unsigned i = 0; i < 30; ++i)
{
- qint64 mid = haveUpperBound ? (lowerBound + upperBound) / 2 : upperBound;
+ qint64 mid = m_startUpperBound;
ExecutionResult er;
if (isCreation())
- er = ethereum()->create(from, value(), m_data, mid, gasPrice(), ethereum()->getDefault(), FudgeFactor::Lenient);
+ er = ethereum()->create(from, value(), m_data, mid, gasPrice(), PendingBlock, FudgeFactor::Lenient);
else
- er = ethereum()->call(from, value(), to, m_data, mid, gasPrice(), ethereum()->getDefault(), FudgeFactor::Lenient);
+ er = ethereum()->call(from, value(), to, m_data, mid, gasPrice(), PendingBlock, FudgeFactor::Lenient);
if (er.excepted == TransactionException::OutOfGas || er.excepted == TransactionException::OutOfGasBase || er.excepted == TransactionException::OutOfGasIntrinsic || er.codeDeposit == CodeDeposit::Failed)
{
- lowerBound = mid;
- if (!haveUpperBound)
- upperBound *= 2;
+ m_startLowerBound = mid;
+ m_startUpperBound *= 2;
}
else
{
- lastGood = er;
- if (haveUpperBound)
- upperBound = mid;
- else
- haveUpperBound = true;
+ // Begin async binary chop for gas calculation..
+ m_lastGood = lastGood;
+ m_lowerBound = m_startLowerBound;
+ m_upperBound = m_startUpperBound;
+ killTimer(m_gasCalcTimer);
+ m_gasCalcTimer = startTimer(0);
+ return GasRequirements{m_upperBound, baseGas, m_upperBound - baseGas, (qint64)lastGood.gasRefunded, lastGood};
}
}
-
- // Dry-run execution to determine gas requirement and any execution errors
-// (qint64)(er.gasUsed + er.gasRefunded + c_callStipend);
- return GasRequirements{upperBound, baseGas, upperBound - baseGas, (qint64)lastGood.gasRefunded, lastGood};
+ return GasRequirements();
}
void Transact::rejigData()
@@ -388,15 +472,12 @@ void Transact::rejigData()
if (!s)
return;
- auto b = ethereum()->balanceAt(s, PendingBlock);
-
- m_allGood = true;
QString htmlInfo;
auto bail = [&](QString he) {
- m_allGood = false;
-// ui->send->setEnabled(false);
- ui->code->setHtml(he + htmlInfo);
+ ui->send->setEnabled(false);
+ m_dataInfo = he + htmlInfo;
+ ui->code->setHtml(m_dataInfo);
};
// Determine m_info.
@@ -424,49 +505,15 @@ void Transact::rejigData()
htmlInfo += "Hex
" + QString(ETH_HTML_DIV(ETH_HTML_MONO)) + QString::fromStdString(toHex(m_data)) + "";
- auto gasReq = determineGasRequirements();
- htmlInfo = QString("INFO Gas required: %1 total = %2 base, %3 exec [%4 refunded later]
").arg(gasReq.neededGas).arg(gasReq.baseGas).arg(gasReq.executionGas).arg(gasReq.refundedGas) + htmlInfo;
-
- if (b < value() + gasReq.baseGas * gasPrice())
- {
- // Not enough - bail.
- bail("ERROR Account doesn't contain enough for paying even the basic amount of gas required.
");
- return;
- }
- if (gasReq.neededGas > m_ethereum->gasLimitRemaining())
- {
- // Not enough - bail.
- bail("ERROR Gas remaining in block isn't enough to allow the gas required.
");
- return;
- }
- if (gasReq.er.excepted != TransactionException::None)
- {
- bail("ERROR " + QString::fromStdString(toString(gasReq.er.excepted)) + "
");
- return;
- }
- if (gasReq.er.codeDeposit == CodeDeposit::Failed)
- {
- bail("ERROR Code deposit failed due to insufficient gas; " + QString::fromStdString(toString(gasReq.er.gasForDeposit)) + " GAS < " + QString::fromStdString(toString(gasReq.er.depositSize)) + " bytes * " + QString::fromStdString(toString(c_createDataGas)) + "GAS/byte
");
- return;
- }
-
// Add Natspec information
if (!isCreation())
- htmlInfo = "INFO " + QString::fromStdString(natspecNotice(toAccount(), m_data)).toHtmlEscaped() + "
" + htmlInfo;
+ htmlInfo = "INFO " + QString::fromStdString(natspecNotice(toAccount().first, m_data)).toHtmlEscaped() + "
" + htmlInfo;
- // Update gas
- if (ui->gas->value() == ui->gas->minimum())
- {
- ui->gas->setMinimum(gasReq.neededGas);
- ui->gas->setValue(gasReq.neededGas);
- }
- else
- ui->gas->setMinimum(gasReq.neededGas);
-
- updateFee();
+ determineGasRequirements();
- ui->code->setHtml(htmlInfo);
-// ui->send->setEnabled(m_allGood);
+ m_dataInfo = htmlInfo;
+ ui->code->setHtml(m_dataInfo);
+ ui->send->setEnabled(true);
}
Secret Transact::findSecret(u256 _totalReq) const
@@ -528,7 +575,7 @@ void Transact::on_send_clicked()
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
- ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice(), nonce);
+ ethereum()->submitTransaction(s, value(), m_data, gas(), gasPrice(), nonce);
#if ETH_SOLIDITY
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
@@ -547,7 +594,7 @@ void Transact::on_send_clicked()
}
else
// TODO: cache like m_data.
- ethereum()->submitTransaction(s, value(), m_main->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice(), nonce);
+ ethereum()->submitTransaction(s, value(), toAccount().first, m_data, gas(), gasPrice(), nonce);
close();
}
@@ -566,8 +613,8 @@ void Transact::on_debug_clicked()
{
Block postState(ethereum()->postState());
Transaction t = isCreation() ?
- Transaction(value(), gasPrice(), ui->gas->value(), m_data, postState.transactionsFrom(from)) :
- Transaction(value(), gasPrice(), ui->gas->value(), m_main->fromString(ui->destination->currentText().toStdString()).first, m_data, postState.transactionsFrom(from));
+ Transaction(value(), gasPrice(), gas(), m_data, postState.transactionsFrom(from)) :
+ Transaction(value(), gasPrice(), gas(), toAccount().first, m_data, postState.transactionsFrom(from));
t.forceSender(from);
Debugger dw(m_main, this);
Executive e(postState, ethereum()->blockChain(), 0);
diff --git a/alethzero/Transact.h b/alethzero/Transact.h
index 8b319c912..723ff07db 100644
--- a/alethzero/Transact.h
+++ b/alethzero/Transact.h
@@ -79,13 +79,16 @@ private:
dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData();
void updateNonce();
+ void updateBounds();
+ void finaliseBounds();
dev::Address fromAccount();
- dev::Address toAccount();
+ std::pair toAccount();
void updateDestination();
void updateFee();
bool isCreation() const;
dev::u256 fee() const;
+ dev::u256 gas() const;
dev::u256 total() const;
dev::u256 value() const;
dev::u256 gasPrice() const;
@@ -95,6 +98,8 @@ private:
std::string natspecNotice(dev::Address _to, dev::bytes const& _data);
dev::Secret findSecret(dev::u256 _totalReq) const;
+ void timerEvent(QTimerEvent*) override;
+
Ui::Transact* ui = nullptr;
unsigned m_backupGas = 0;
@@ -104,7 +109,14 @@ private:
dev::eth::Client* m_ethereum = nullptr;
MainFace* m_main = nullptr;
NatSpecFace* m_natSpecDB = nullptr;
- bool m_allGood = false;
+
+ QString m_dataInfo;
+ qint64 m_startLowerBound = 0;
+ qint64 m_startUpperBound = 0;
+ qint64 m_lowerBound = 0;
+ qint64 m_upperBound = 0;
+ eth::ExecutionResult m_lastGood;
+ int m_gasCalcTimer = 0;
};
}
diff --git a/alethzero/Transact.ui b/alethzero/Transact.ui
index bd19808fd..94b329842 100644
--- a/alethzero/Transact.ui
+++ b/alethzero/Transact.ui
@@ -6,7 +6,7 @@
0
0
- 543
+ 604
695