Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

EIP658: Status code in receipt #4275

Merged
merged 4 commits into from
Jul 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libethcore/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ DEV_SIMPLE_EXCEPTION(InvalidUncleParentHash);
DEV_SIMPLE_EXCEPTION(InvalidNumber);
DEV_SIMPLE_EXCEPTION(InvalidZeroSignatureTransaction);
DEV_SIMPLE_EXCEPTION(InvalidTransactionReceiptFormat);
DEV_SIMPLE_EXCEPTION(TransactionReceiptVersionError);
DEV_SIMPLE_EXCEPTION(BlockNotFound);
DEV_SIMPLE_EXCEPTION(UnknownParent);
DEV_SIMPLE_EXCEPTION(AddressAlreadyUsed);
Expand Down
9 changes: 8 additions & 1 deletion libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,14 @@ bool Block::sealBlock(bytesConstRef _header)
h256 Block::stateRootBeforeTx(unsigned _i) const
{
_i = min<unsigned>(_i, m_transactions.size());
return (_i > 0 ? receipt(_i - 1).stateRoot() : m_previousBlock.stateRoot());
try
{
return (_i > 0 ? receipt(_i - 1).stateRoot() : m_previousBlock.stateRoot());
}
catch (TransactionReceiptVersionError const&)
{
return {};
}
}

LogBloom Block::logBloom() const
Expand Down
3 changes: 2 additions & 1 deletion libethereum/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ bool Executive::go(OnOpFunc const& _onOp)
return true;
}

void Executive::finalize()
bool Executive::finalize()
{
// Accumulate refunds for suicides.
if (m_ext)
Expand Down Expand Up @@ -517,6 +517,7 @@ void Executive::finalize()
m_res->newAddress = m_newAddress;
m_res->gasRefunded = m_ext ? m_ext->sub.refunds : 0;
}
return (m_excepted == TransactionException::None);
}

void Executive::revert()
Expand Down
3 changes: 2 additions & 1 deletion libethereum/Executive.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ class Executive
void initialize(Transaction const& _transaction);
/// Finalise a transaction previously set up with initialize().
/// @warning Only valid after initialize() and execute(), and possibly go().
void finalize();
/// @returns true if the outermost execution halted normally, false if exceptionally halted.
bool finalize();
/// Begins execution of a transaction. You must call finalize() following this.
/// @returns true if the transaction is done, false if go() must be called.
bool execute();
Expand Down
9 changes: 5 additions & 4 deletions libethereum/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; }
namespace
{

void executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp)
/// @returns true when normally halted; false when exceptionally halted.
bool executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp)
{
_e.initialize(_t);

if (!_e.execute())
_e.go(_onOp);
_e.finalize();
return _e.finalize();
}

}
Expand Down Expand Up @@ -564,7 +565,7 @@ std::pair<ExecutionResult, TransactionReceipt> State::execute(EnvInfo const& _en
e.setResultRecipient(res);

u256 const startGasUsed = _envInfo.gasUsed();
executeTransaction(e, _t, onOp);
bool const statusCode = executeTransaction(e, _t, onOp);

bool removeEmptyAccounts = false;
switch (_p)
Expand All @@ -581,7 +582,7 @@ std::pair<ExecutionResult, TransactionReceipt> State::execute(EnvInfo const& _en
}

TransactionReceipt const receipt = _envInfo.number() >= _sealEngine.chainParams().u256Param("metropolisForkBlock") ?
TransactionReceipt(startGasUsed + e.gasUsed(), e.logs()) :
TransactionReceipt(statusCode, startGasUsed + e.gasUsed(), e.logs()) :
TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs());
return make_pair(res, receipt);
}
Expand Down
73 changes: 54 additions & 19 deletions libethereum/TransactionReceipt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,89 @@
#include "TransactionReceipt.h"
#include <libethcore/Exceptions.h>

#include <boost/variant/get.hpp>

using namespace std;
using namespace dev;
using namespace dev::eth;

TransactionReceipt::TransactionReceipt(bytesConstRef _rlp)
{
RLP r(_rlp);
if (!r.isList() || r.itemCount() < 3 || r.itemCount() > 4)
if (!r.isList() || r.itemCount() != 4)
BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat());

size_t gasUsedIndex = 0;
if (r.itemCount() == 4)
{
m_stateRoot = (h256)r[0];
gasUsedIndex = 1;
}

m_gasUsed = (u256)r[gasUsedIndex];
m_bloom = (LogBloom)r[gasUsedIndex + 1];
for (auto const& i : r[gasUsedIndex + 2])
if (!r[0].isData())
BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat());

if (r[0].size() == 32)
m_statusCodeOrStateRoot = (h256)r[0];
else if (r[0].size() == 1)
m_statusCodeOrStateRoot = (uint8_t)r[0];
else
BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat());

m_gasUsed = (u256)r[1];
m_bloom = (LogBloom)r[2];
for (auto const& i : r[3])
m_log.emplace_back(i);

}

TransactionReceipt::TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log):
m_stateRoot(_root),
TransactionReceipt::TransactionReceipt(h256 const& _root, u256 const& _gasUsed, LogEntries const& _log):
m_statusCodeOrStateRoot(_root),
m_gasUsed(_gasUsed),
m_bloom(eth::bloom(_log)),
m_log(_log)
{}

TransactionReceipt::TransactionReceipt(uint8_t _status, u256 const& _gasUsed, LogEntries const& _log):
m_statusCodeOrStateRoot(_status),
m_gasUsed(_gasUsed),
m_bloom(eth::bloom(_log)),
m_log(_log)
{}

void TransactionReceipt::streamRLP(RLPStream& _s) const
{
if (m_stateRoot)
_s.appendList(4) << m_stateRoot;
_s.appendList(4);
if (hasStatusCode())
_s << statusCode();
else
_s.appendList(3);

_s << stateRoot();
_s << m_gasUsed << m_bloom;

_s.appendList(m_log.size());
for (LogEntry const& l: m_log)
l.streamRLP(_s);
}

bool TransactionReceipt::hasStatusCode() const
{
return m_statusCodeOrStateRoot.which() == 0;
}

uint8_t TransactionReceipt::statusCode() const
{
if (hasStatusCode())
return boost::get<uint8_t>(m_statusCodeOrStateRoot);
else
BOOST_THROW_EXCEPTION(TransactionReceiptVersionError());
}

h256 const& TransactionReceipt::stateRoot() const
{
if (hasStatusCode())
BOOST_THROW_EXCEPTION(TransactionReceiptVersionError());
else
return boost::get<h256>(m_statusCodeOrStateRoot);
}

std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionReceipt const& _r)
{
_out << "Root: " << _r.stateRoot() << std::endl;
if (_r.hasStatusCode())
_out << "Status: " << _r.statusCode() << std::endl;
else
_out << "Root: " << _r.stateRoot() << std::endl;
_out << "Gas used: " << _r.gasUsed() << std::endl;
_out << "Logs: " << _r.log().size() << " entries:" << std::endl;
for (LogEntry const& i: _r.log())
Expand Down
21 changes: 15 additions & 6 deletions libethereum/TransactionReceipt.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,32 @@
#include <libdevcore/RLP.h>
#include <libevm/ExtVMFace.h>

#include <boost/variant/variant.hpp>

namespace dev
{

namespace eth
{

/// Transaction receipt, constructed either from RLP representation or from individual values.
/// State Root is optional, m_stateRoot is h256() when it is empty (for transactions after Metropolis)
/// Either a state root or a status code is contained. m_hasStatusCode is true when it contains a status code.
/// Empty state root is not included into RLP-encoding.
class TransactionReceipt
{
public:
TransactionReceipt(bytesConstRef _rlp);
TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log);
TransactionReceipt(u256 _gasUsed, LogEntries const& _log) : TransactionReceipt(h256(), _gasUsed, _log) {}

h256 const& stateRoot() const { return m_stateRoot; }
TransactionReceipt(h256 const& _root, u256 const& _gasUsed, LogEntries const& _log);
TransactionReceipt(uint8_t _status, u256 const& _gasUsed, LogEntries const& _log);

/// @returns true if the receipt has a status code. Otherwise the receipt has a state root (pre-EIP658).
bool hasStatusCode() const;
/// @returns the state root.
/// @throw TransactionReceiptVersionError when the receipt has a status code instead of a state root.
h256 const& stateRoot() const;
/// @returns the status code.
/// @throw TransactionReceiptVersionError when the receipt has a state root instead of a status code.
uint8_t statusCode() const;
u256 const& gasUsed() const { return m_gasUsed; }
LogBloom const& bloom() const { return m_bloom; }
LogEntries const& log() const { return m_log; }
Expand All @@ -52,7 +61,7 @@ class TransactionReceipt
bytes rlp() const { RLPStream s; streamRLP(s); return s.out(); }

private:
h256 m_stateRoot;
boost::variant<uint8_t,h256> m_statusCodeOrStateRoot;
u256 m_gasUsed;
LogBloom m_bloom;
LogEntries m_log;
Expand Down
5 changes: 4 additions & 1 deletion libweb3jsonrpc/JsonHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t)
Json::Value toJson(dev::eth::TransactionReceipt const& _t)
{
Json::Value res;
res["stateRoot"] = toJS(_t.stateRoot());
if (_t.hasStatusCode())
res["statusCode"] = toJS(_t.statusCode());
else
res["stateRoot"] = toJS(_t.stateRoot());
res["gasUsed"] = toJS(_t.gasUsed());
res["bloom"] = toJS(_t.bloom());
res["log"] = dev::toJson(_t.log());
Expand Down
2 changes: 1 addition & 1 deletion test/jsontests
Submodule jsontests updated 323 files