diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp
index 6482b691d..821629906 100644
--- a/alethzero/DappLoader.cpp
+++ b/alethzero/DappLoader.cpp
@@ -72,20 +72,19 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri)
string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
- address = abiOut
(web3()->ethereum()->call(address, abiIn("addr(string32)", name)));
+ address = abiOut(web3()->ethereum()->call(address, abiIn("addr(string32)", name)).output);
domainParts.append(parts[partIndex]);
if (!address)
{
//we have the address of the last part, try to get content hash
- contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)));
+ contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)).output);
if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address");
}
++partIndex;
}
-
- string32 contentUrl = abiOut(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)));
+ string32 contentUrl = abiOut(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)).output);
QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/');
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 091e4ce98..967bc6b56 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -284,12 +284,12 @@ void Main::installWatches()
Address Main::getNameReg() const
{
- return abiOut(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)));
+ return abiOut(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output);
}
Address Main::getCurrencies() const
{
- return abiOut(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)));
+ return abiOut(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output);
}
void Main::installNameRegWatch()
@@ -470,7 +470,7 @@ QString Main::pretty(dev::Address _a) const
if (g_newNameReg)
{
- QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)))));
+ QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)).output)));
if (s.size())
return s;
}
@@ -575,7 +575,7 @@ Address Main::fromString(QString const& _n) const
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
- Address a = abiOut(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))));
+ Address a = abiOut(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))).output);
if (a)
return a;
}
diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp
index e28fcd39f..84cc41dd1 100644
--- a/evmjit/libevmjit-cpp/JitVM.cpp
+++ b/evmjit/libevmjit-cpp/JitVM.cpp
@@ -69,8 +69,8 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
BOOST_THROW_EXCEPTION(BadJumpDestination());
case ReturnCode::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas());
- case ReturnCode::StackTooSmall:
- BOOST_THROW_EXCEPTION(StackTooSmall());
+ case ReturnCode::StackUnderflow:
+ BOOST_THROW_EXCEPTION(StackUnderflow());
case ReturnCode::BadInstruction:
BOOST_THROW_EXCEPTION(BadInstruction());
case ReturnCode::LinkerWorkaround: // never happens
diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h
index 62731292f..e564e0702 100644
--- a/evmjit/libevmjit/Common.h
+++ b/evmjit/libevmjit/Common.h
@@ -33,7 +33,7 @@ enum class ReturnCode
// Standard error codes
OutOfGas = -1,
- StackTooSmall = -2,
+ StackUnderflow = -2,
BadJumpDestination = -3,
BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp
index de48e8ef9..2039b5d10 100644
--- a/evmjit/libevmjit/Compiler.cpp
+++ b/evmjit/libevmjit/Compiler.cpp
@@ -516,7 +516,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
auto val = stack.pop();
static_cast(val);
// Generate a dummy use of val to make sure that a get(0) will be emitted at this point,
- // so that StackTooSmall will be thrown
+ // so that StackUnderflow will be thrown
// m_builder.CreateICmpEQ(val, val, "dummy");
break;
}
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 4d10679dd..fb29ffb6a 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -491,9 +491,9 @@ void Client::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes
m_tq.attemptImport(t.rlp());
}
-bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
+ExecutionResult Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
{
- bytes out;
+ ExecutionResult ret;
try
{
u256 n;
@@ -505,18 +505,41 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
- u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false);
- (void)gasUsed; // TODO: do something with gasused which it returns.
+ ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted);
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
- return out;
+ return ret;
}
-bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
+ExecutionResult Client::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
{
+ ExecutionResult ret;
+ try
+ {
+ u256 n;
+ State temp;
+ // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
+ {
+ ReadGuard l(x_stateDB);
+ temp = asOf(_blockNumber);
+ n = temp.transactionsFrom(toAddress(_secret));
+ }
+ Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
+ ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted);
+ }
+ catch (...)
+ {
+ // TODO: Some sort of notification of failure.
+ }
+ return ret;
+}
+
+ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
+{
+ ExecutionResult ret;
try
{
State temp;
@@ -527,16 +550,14 @@ bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u2
}
Executive e(temp, LastHashes(), 0);
if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()))
- {
e.go();
- return e.out().toBytes();
- }
+ ret = e.executionResult();
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
- return bytes();
+ return ret;
}
Address Client::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
diff --git a/libethereum/Client.h b/libethereum/Client.h
index 6048715c4..426c78ca7 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -212,23 +212,27 @@ public:
void setGasPricer(std::shared_ptr _gp) { m_gp = _gp; }
/// Submits the given message-call transaction.
- virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
+ virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
- virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
+ virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
- virtual void inject(bytesConstRef _rlp);
+ virtual void inject(bytesConstRef _rlp) override;
/// Blocks until all pending transactions have been processed.
- virtual void flushTransactions();
+ virtual void flushTransactions() override;
/// Makes the given call. Nothing is recorded into the state.
- virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0);
+ virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) override;
+
+ /// Does the given creation. Nothing is recorded into the state.
+ /// @returns the pair of the Address of the created contract together with its code.
+ virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) override;
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
- virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
+ ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
// Informational stuff
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index e009b49fb..b44caf4ee 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -53,7 +53,16 @@ void Executive::accrueSubState(SubState& _parentContext)
bool Executive::setup(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
- m_t = Transaction(_rlp, CheckSignature::Sender);
+ try
+ {
+ m_t = Transaction(_rlp, CheckSignature::Sender);
+ }
+ catch (...)
+ {
+ clog(StateDetail) << "Invalid Signature";
+ m_excepted = TransactionException::InvalidSignature;
+ throw;
+ }
return setup();
}
@@ -66,6 +75,7 @@ bool Executive::setup()
if (m_t.nonce() != nonceReq)
{
clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
+ m_excepted = TransactionException::InvalidNonce;
BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce()));
}
@@ -120,7 +130,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
if (_gas < g)
{
m_endGas = 0;
- m_excepted = true;
+ m_excepted = TransactionException::OutOfGasBase;
}
else
{
@@ -200,9 +210,15 @@ bool Executive::go(OnOpFunc const& _onOp)
if (m_isCreation)
{
if (m_out.size() * c_createDataGas <= m_endGas)
+ {
+ m_codeDeposit = CodeDeposit::Success;
m_endGas -= m_out.size() * c_createDataGas;
+ }
else
+ {
+ m_codeDeposit = CodeDeposit::Failed;
m_out.reset();
+ }
m_s.m_cache[m_newAddress].setCode(m_out.toBytes());
}
}
@@ -214,7 +230,7 @@ bool Executive::go(OnOpFunc const& _onOp)
{
clog(StateSafeExceptions) << "Safe VM Exception. " << diagnostic_information(_e);
m_endGas = 0;
- m_excepted = true;
+ m_excepted = toTransactionException(_e);
m_ext->revert();
}
catch (Exception const& _e)
diff --git a/libethereum/Executive.h b/libethereum/Executive.h
index 2e89f0623..d04a39da8 100644
--- a/libethereum/Executive.h
+++ b/libethereum/Executive.h
@@ -101,7 +101,10 @@ public:
/// @returns the new address for the created contract in the CREATE operation.
h160 newAddress() const { return m_newAddress; }
/// @returns true iff the operation ended with a VM exception.
- bool excepted() const { return m_excepted; }
+ bool excepted() const { return m_excepted != TransactionException::None; }
+
+ /// Get the above in an amalgamated fashion.
+ ExecutionResult executionResult() const { return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit); }
private:
bool setup();
@@ -116,7 +119,8 @@ private:
unsigned m_depth = 0; ///< The context's call-depth.
bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called.
- bool m_excepted = false; ///< True if the VM execution resulted in an exception.
+ CodeDeposit m_codeDeposit = CodeDeposit::None; ///< True if an attempted deposit failed due to lack of gas.
+ TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception.
u256 m_endGas; ///< The final amount of gas for the transaction.
Transaction m_t; ///< The original transaction. Set by setup().
diff --git a/libethereum/Interface.h b/libethereum/Interface.h
index 83305af3e..dfbd47704 100644
--- a/libethereum/Interface.h
+++ b/libethereum/Interface.h
@@ -73,7 +73,11 @@ public:
virtual void flushTransactions() = 0;
/// Makes the given call. Nothing is recorded into the state.
- virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0;
+ virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0;
+
+ /// Does the given creation. Nothing is recorded into the state.
+ /// @returns the pair of the Address of the created contract together with its code.
+ virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0;
// [STATE-QUERY API]
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 9bfc0c08c..47e6542db 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -1048,18 +1048,18 @@ LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const
return ret;
}
-u256 State::execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output, bool _commit)
+ExecutionResult State::execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p)
{
- return execute(getLastHashes(_bc, _bc.number()), &_rlp, o_output, _commit);
+ return execute(getLastHashes(_bc, _bc.number()), &_rlp, _p);
}
-u256 State::execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output, bool _commit)
+ExecutionResult State::execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p)
{
- return execute(getLastHashes(_bc, _bc.number()), _rlp, o_output, _commit);
+ return execute(getLastHashes(_bc, _bc.number()), _rlp, _p);
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
-u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit)
+ExecutionResult State::execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
@@ -1093,41 +1093,38 @@ u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output,
ctrace << old.diff(*this);
#endif
- if (o_output)
- *o_output = e.out().toBytes();
-
- if (!_commit)
- {
+ if (_p == Permanence::Reverted)
m_cache.clear();
- return e.gasUsed();
- }
-
- commit();
-
-#if ETH_PARANOIA && !ETH_FATDB
- ctrace << "Executed; now" << rootHash();
- ctrace << old.diff(*this);
-
- paranoia("after execution commit.", true);
-
- if (e.t().receiveAddress())
+ else
{
- EnforceRefs r(m_db, true);
- if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty())
+ commit();
+
+#if ETH_PARANOIA && !ETH_FATDB
+ ctrace << "Executed; now" << rootHash();
+ ctrace << old.diff(*this);
+
+ paranoia("after execution commit.", true);
+
+ if (e.t().receiveAddress())
{
- cwarn << "TRIE immediately after execution; no node for receiveAddress";
- BOOST_THROW_EXCEPTION(InvalidTrie());
+ EnforceRefs r(m_db, true);
+ if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty())
+ {
+ cwarn << "TRIE immediately after execution; no node for receiveAddress";
+ BOOST_THROW_EXCEPTION(InvalidTrie());
+ }
}
- }
#endif
+
+ // TODO: CHECK TRIE after level DB flush to make sure exactly the same.
+
+ // Add to the user-originated transactions that we've executed.
+ m_transactions.push_back(e.t());
+ m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()));
+ m_transactionSet.insert(e.t().sha3());
+ }
- // TODO: CHECK TRIE after level DB flush to make sure exactly the same.
-
- // Add to the user-originated transactions that we've executed.
- m_transactions.push_back(e.t());
- m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()));
- m_transactionSet.insert(e.t().sha3());
- return e.gasUsed();
+ return e.executionResult();
}
State State::fromPending(unsigned _i) const
diff --git a/libethereum/State.h b/libethereum/State.h
index bfa60e452..36d3e7c09 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -84,6 +84,12 @@ protected:
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; }
};
+enum class Permanence
+{
+ Reverted,
+ Committed
+};
+
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@@ -185,10 +191,10 @@ public:
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
- u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true);
- u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
- u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); }
- u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
+ ExecutionResult execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p = Permanence::Committed);
+ ExecutionResult execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
+ ExecutionResult execute(LastHashes const& _lh, bytes const& _rlp, Permanence _p = Permanence::Committed) { return execute(_lh, &_rlp, _p); }
+ ExecutionResult execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp
index a89083648..3a092bf25 100644
--- a/libethereum/Transaction.cpp
+++ b/libethereum/Transaction.cpp
@@ -21,8 +21,10 @@
#include
#include
+#include
#include
#include
+#include
#include "Transaction.h"
using namespace std;
using namespace dev;
@@ -30,6 +32,25 @@ using namespace dev::eth;
#define ETH_ADDRESS_DEBUG 0
+std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _er)
+{
+ _out << "{" << _er.gasUsed << ", " << _er.newAddress << ", " << toHex(_er.output) << "}";
+ return _out;
+}
+
+TransactionException dev::eth::toTransactionException(VMException const& _e)
+{
+ if (!!dynamic_cast(&_e))
+ return TransactionException::BadInstruction;
+ if (!!dynamic_cast(&_e))
+ return TransactionException::BadJumpDestination;
+ if (!!dynamic_cast(&_e))
+ return TransactionException::OutOfGas;
+ if (!!dynamic_cast(&_e))
+ return TransactionException::StackUnderflow;
+ return TransactionException::Unknown;
+}
+
Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
{
int field = 0;
diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h
index 7dd28f7c6..85543a3fc 100644
--- a/libethereum/Transaction.h
+++ b/libethereum/Transaction.h
@@ -44,6 +44,46 @@ enum class CheckSignature
Sender
};
+enum class TransactionException
+{
+ None = 0,
+ Unknown,
+ InvalidSignature,
+ InvalidNonce,
+ NotEnoughCash,
+ OutOfGasBase, ///< Too little gas to pay for the base transaction cost.
+ BlockGasLimitReached,
+ BadInstruction,
+ BadJumpDestination,
+ OutOfGas, ///< Ran out of gas executing code of the transaction.
+ StackUnderflow
+};
+
+enum class CodeDeposit
+{
+ None = 0,
+ Failed,
+ Success
+};
+
+class VMException;
+
+TransactionException toTransactionException(VMException const& _e);
+
+/// Description of the result of executing a transaction.
+struct ExecutionResult
+{
+ ExecutionResult() = default;
+ ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit) {}
+ u256 gasUsed;
+ TransactionException excepted = TransactionException::Unknown;
+ Address newAddress;
+ bytes output;
+ CodeDeposit codeDeposit = CodeDeposit::None;
+};
+
+std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er);
+
/// Encodes a transaction, ready to be exported to or freshly imported from RLP.
class Transaction
{
diff --git a/libevm/VM.h b/libevm/VM.h
index f2c773e4b..3efb3b119 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -56,7 +56,7 @@ public:
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
- void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } }
+ void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 curPC() const { return m_curPC; }
diff --git a/libevm/VMFace.h b/libevm/VMFace.h
index f8c20feb1..7b99b5bfd 100644
--- a/libevm/VMFace.h
+++ b/libevm/VMFace.h
@@ -31,7 +31,7 @@ struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
-struct StackTooSmall: virtual VMException {};
+struct StackUnderflow: virtual VMException {};
/// EVM Virtual Machine interface
class VMFace
diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp
index 6f3b8c831..76c659fba 100644
--- a/mix/ClientModel.cpp
+++ b/mix/ClientModel.cpp
@@ -534,7 +534,7 @@ void ClientModel::onNewTransaction()
{
function = funcDef->name();
ContractCallDataEncoder encoder;
- QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue);
+ QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.result.output);
returned += "(";
returned += returnValues.join(", ");
returned += ")";
diff --git a/mix/MachineStates.h b/mix/MachineStates.h
index 310d5cacd..a97ee0787 100644
--- a/mix/MachineStates.h
+++ b/mix/MachineStates.h
@@ -29,6 +29,7 @@ along with cpp-ethereum. If not, see .
#include
#include
#include
+#include
#include
namespace dev
@@ -74,7 +75,7 @@ namespace mix
std::vector machineStates;
std::vector transactionData;
std::vector executionCode;
- bytes returnValue;
+ dev::eth::ExecutionResult result;
dev::Address address;
dev::Address sender;
dev::Address contractAddress;
diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp
index 74e8ca9ef..a8da07a55 100644
--- a/mix/MixClient.cpp
+++ b/mix/MixClient.cpp
@@ -175,7 +175,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
execution.finalize();
ExecutionResult d;
- d.returnValue = execution.out().toVector();
+ d.result = execution.executionResult();
d.machineStates = machineStates;
d.executionCode = std::move(codes);
d.transactionData = std::move(data);
@@ -191,7 +191,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state
if (!_call)
{
- _state.execute(lastHashes, rlp, nullptr, true);
+ _state.execute(lastHashes, rlp);
// collect watches
h256Set changed;
Guard l(m_filterLock);
@@ -276,7 +276,7 @@ void MixClient::flushTransactions()
{
}
-bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
+dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
{
u256 n;
State temp;
@@ -289,7 +289,23 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _
bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true);
- return lastExecution().returnValue;
+ return lastExecution().result;
+}
+
+dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber)
+{
+ u256 n;
+ State temp;
+ {
+ ReadGuard lr(x_state);
+ temp = asOf(_blockNumber);
+ n = temp.transactionsFrom(toAddress(_secret));
+ }
+ Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
+ bytes rlp = t.rlp();
+ WriteGuard lw(x_state); //TODO: lock is required only for last execution state
+ executeTransaction(t, temp, true);
+ return lastExecution().result;
}
u256 MixClient::balanceAt(Address _a, int _block) const
diff --git a/mix/MixClient.h b/mix/MixClient.h
index 575871899..c8024a011 100644
--- a/mix/MixClient.h
+++ b/mix/MixClient.h
@@ -52,7 +52,8 @@ public:
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override;
void inject(bytesConstRef _rlp) override;
void flushTransactions() override;
- bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override;
+ dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override;
+ dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override;
u256 balanceAt(Address _a, int _block) const override;
u256 countAt(Address _a, int _block) const override;
u256 stateAt(Address _a, u256 _l, int _block) const override;
diff --git a/test/checkRandomStateTest.cpp b/test/checkRandomStateTest.cpp
index 17e785f60..0fa7233b4 100644
--- a/test/checkRandomStateTest.cpp
+++ b/test/checkRandomStateTest.cpp
@@ -87,7 +87,7 @@ bool doStateTest(mValue& _v)
try
{
- theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output);
+ output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
}
catch (Exception const& _e)
{
diff --git a/test/createRandomStateTest.cpp b/test/createRandomStateTest.cpp
index 13b622bb1..c03deca80 100644
--- a/test/createRandomStateTest.cpp
+++ b/test/createRandomStateTest.cpp
@@ -162,7 +162,7 @@ void doStateTests(json_spirit::mValue& _v)
try
{
- theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx, &output);
+ output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx).output;
}
catch (Exception const& _e)
{
diff --git a/test/state.cpp b/test/state.cpp
index 162ae5f34..4ab59f7a1 100644
--- a/test/state.cpp
+++ b/test/state.cpp
@@ -63,7 +63,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
try
{
Listener::ExecTimeGuard guard{i.first};
- theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output);
+ output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
}
catch (Exception const& _e)
{