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

Commit

Permalink
Merge pull request #4275 from ethereum/status_code_in_receipt
Browse files Browse the repository at this point in the history
EIP658: Status code in receipt
  • Loading branch information
pirapira authored Jul 20, 2017
2 parents ec8cb4c + c9d14fc commit b352d83
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 34 deletions.
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

0 comments on commit b352d83

Please sign in to comment.