diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp
index 34a37c241..998f1e160 100644
--- a/alethzero/Transact.cpp
+++ b/alethzero/Transact.cpp
@@ -323,6 +323,54 @@ string Transact::natspecNotice(Address _to, bytes const& _data)
return "Destination not a contract.";
}
+Address Transact::toAccount()
+{
+ return isCreation() ? Address() : m_context->fromString(ui->destination->currentText().toStdString()).first;
+}
+
+GasRequirements Transact::determineGasRequirements()
+{
+ // Determine the minimum amount of gas we need to play...
+ qint64 baseGas = (qint64)Transaction::gasRequired(m_data, 0);
+
+ Address from = fromAccount();
+ Address to = toAccount();
+ 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.
+ {
+ qint64 mid = haveUpperBound ? (lowerBound + upperBound) / 2 : upperBound;
+ cdebug << "Trying" << mid;
+ ExecutionResult er;
+ if (isCreation())
+ er = ethereum()->create(from, value(), m_data, mid, gasPrice(), ethereum()->getDefault(), FudgeFactor::Lenient);
+ else
+ er = ethereum()->call(from, value(), to, m_data, mid, gasPrice(), ethereum()->getDefault(), FudgeFactor::Lenient);
+ cdebug << toString(er.excepted);
+ if (er.excepted == TransactionException::OutOfGas || er.excepted == TransactionException::OutOfGasBase || er.excepted == TransactionException::OutOfGasIntrinsic || er.codeDeposit == CodeDeposit::Failed)
+ {
+ lowerBound = mid;
+ if (!haveUpperBound)
+ upperBound *= 2;
+ }
+ else
+ {
+ lastGood = er;
+ if (haveUpperBound)
+ upperBound = mid;
+ else
+ haveUpperBound = true;
+ }
+ }
+
+ // 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};
+}
+
void Transact::rejigData()
{
if (!ethereum())
@@ -370,56 +418,44 @@ void Transact::rejigData()
htmlInfo += "
Hex
" + QString(ETH_HTML_DIV(ETH_HTML_MONO)) + QString::fromStdString(toHex(m_data)) + "";
- // Determine the minimum amount of gas we need to play...
- qint64 baseGas = (qint64)Transaction::gasRequired(m_data, 0);
- qint64 gasNeeded = 0;
+ 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() + baseGas * gasPrice())
+ 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;
}
- else
- gasNeeded = (qint64)min(ethereum()->gasLimitRemaining(), ((b - value()) / max(gasPrice(), 1)));
-
- // Dry-run execution to determine gas requirement and any execution errors
- Address to;
- ExecutionResult er;
- if (isCreation())
- er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice());
- else
+ if (gasReq.neededGas > m_ethereum->gasLimitRemaining())
{
- // TODO: cache like m_data.
- to = m_context->fromString(ui->destination->currentText().toStdString()).first;
- er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
+ // Not enough - bail.
+ bail("ERROR Gas remaining in block isn't enough to allow the gas required.
");
+ return;
}
- gasNeeded = (qint64)(er.gasUsed + er.gasRefunded + c_callStipend);
- htmlInfo = QString("INFO Gas required: %1 total = %2 base, %3 exec [%4 refunded later]
").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;
-
- if (er.excepted != TransactionException::None)
+ if (gasReq.er.excepted != TransactionException::None)
{
- bail("ERROR " + QString::fromStdString(toString(er.excepted)) + "
");
+ bail("ERROR " + QString::fromStdString(toString(gasReq.er.excepted)) + "
");
return;
}
- if (er.codeDeposit == CodeDeposit::Failed)
+ if (gasReq.er.codeDeposit == CodeDeposit::Failed)
{
- bail("ERROR Code deposit failed due to insufficient gas; " + QString::fromStdString(toString(er.gasForDeposit)) + " GAS < " + QString::fromStdString(toString(er.depositSize)) + " bytes * " + QString::fromStdString(toString(c_createDataGas)) + "GAS/byte
");
+ 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(to, m_data)).toHtmlEscaped() + "
" + htmlInfo;
+ htmlInfo = "INFO " + QString::fromStdString(natspecNotice(toAccount(), m_data)).toHtmlEscaped() + "
" + htmlInfo;
// Update gas
if (ui->gas->value() == ui->gas->minimum())
{
- ui->gas->setMinimum(gasNeeded);
- ui->gas->setValue(gasNeeded);
+ ui->gas->setMinimum(gasReq.neededGas);
+ ui->gas->setValue(gasReq.neededGas);
}
else
- ui->gas->setMinimum(gasNeeded);
+ ui->gas->setMinimum(gasReq.neededGas);
updateFee();
diff --git a/alethzero/Transact.h b/alethzero/Transact.h
index a1ce544f9..9b2c77a6f 100644
--- a/alethzero/Transact.h
+++ b/alethzero/Transact.h
@@ -33,6 +33,15 @@ namespace Ui { class Transact; }
namespace dev { namespace eth { class Client; } }
namespace dev { namespace solidity { class CompilerStack; } }
+struct GasRequirements
+{
+ qint64 neededGas;
+ qint64 baseGas;
+ qint64 executionGas;
+ qint64 refundedGas;
+ dev::eth::ExecutionResult er;
+};
+
class Transact: public QDialog
{
Q_OBJECT
@@ -65,6 +74,7 @@ private:
void updateNonce();
dev::Address fromAccount();
+ dev::Address toAccount();
void updateDestination();
void updateFee();
bool isCreation() const;
@@ -73,6 +83,7 @@ private:
dev::u256 value() const;
dev::u256 gasPrice() const;
dev::Address to() const;
+ GasRequirements determineGasRequirements();
std::string natspecNotice(dev::Address _to, dev::bytes const& _data);
dev::Secret findSecret(dev::u256 _totalReq) const;
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index b38db9c8b..9921342d7 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -394,7 +394,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c
// Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r;
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500)
- r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles);
+ r = import(block.verified, _stateDB, (ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles) != 0);
fresh += r.liveBlocks;
dead += r.deadBlocks;
goodTransactions.reserve(goodTransactions.size() + r.goodTranactions.size());
@@ -1278,6 +1278,7 @@ Block BlockChain::genesisBlock(OverlayDB const& _db)
dev::eth::commit(m_genesisState, ret.mutableState().m_state); // bit horrible. maybe consider a better way of constructing it?
ret.mutableState().db().commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(m_genesisBlock);
+ ret.resetCurrent();
return ret;
}
diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp
index 71c359093..60ac3f32d 100644
--- a/libethereum/ClientBase.cpp
+++ b/libethereum/ClientBase.cpp
@@ -94,7 +94,7 @@ ExecutionResult ClientBase::create(Address const& _from, u256 _value, bytes cons
Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
- temp.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
+ temp.mutableState().addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index 7eb37ff99..839d69216 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -383,7 +383,7 @@ bool Executive::go(OnOpFunc const& _onOp)
}
catch (VMException const& _e)
{
- clog(StateSafeExceptions) << "Safe VM Exception. " << diagnostic_information(_e);
+ cnote/*clog(StateSafeExceptions)*/ << "Safe VM Exception. " << diagnostic_information(_e);
m_gas = 0;
m_excepted = toTransactionException(_e);
m_ext->revert();
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index b7367a64f..bd5feacb0 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -485,7 +485,7 @@ std::pair State::execute(EnvInfo const& _en
else
{
commit();
-
+
#if ETH_PARANOIA && !ETH_FATDB
ctrace << "Executed; now" << rootHash();
ctrace << old.diff(*this);
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index a24420d43..5b6578ed8 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -45,7 +45,18 @@ v8::Handle JSV8RPCSend(v8::Arguments const& _args)
v8::Local vals[1] = {_args[0]->ToObject()};
v8::Local stringifiedArg = stringifyFunc->Call(stringifyFunc, 1, vals);
v8::String::Utf8Value str(stringifiedArg);
- that->onSend(*str);
+ try
+ {
+ that->onSend(*str);
+ }
+ catch (std::exception const& _e)
+ {
+ return v8::ThrowException(v8::String::New(_e.what()));
+ }
+ catch (...)
+ {
+ return v8::ThrowException(v8::String::New("Unknown C++ exception."));
+ }
v8::Local values[1] = {v8::String::New(that->lastResponse())};
return parseFunc->Call(parseFunc, 1, values);
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 4bd5a126c..b3b3d5bf3 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -742,9 +742,14 @@ void Host::keepAlivePeers()
return;
RecursiveGuard l(x_sessions);
- for (auto p: m_sessions)
- if (auto pp = p.second.lock())
- pp->ping();
+ for (auto it = m_sessions.begin(); it != m_sessions.end();)
+ if (auto p = it->second.lock())
+ {
+ p->ping();
+ ++it;
+ }
+ else
+ it = m_sessions.erase(it);
m_lastPing = chrono::steady_clock::now();
}