Merge pull request #11050 from ethereum/isoltest-effects-events

[isoltest] Add support for events using call side-effects.
This commit is contained in:
chriseth 2021-05-31 14:38:14 +02:00 committed by GitHub
commit c09dc6144c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 663 additions and 724 deletions

View File

@ -27,6 +27,8 @@
#include <test/evmc/evmc.hpp>
#include <test/libsolidity/util/SoltestTypes.h>
#include <libsolutil/CommonIO.h>
#include <libsolutil/FunctionSelector.h>
@ -34,6 +36,8 @@
#include <boost/test/framework.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <range/v3/range.hpp>
#include <range/v3/view/transform.hpp>
#include <cstdlib>
@ -41,6 +45,7 @@ using namespace std;
using namespace solidity;
using namespace solidity::util;
using namespace solidity::test;
using namespace solidity::frontend::test;
ExecutionFramework::ExecutionFramework():
ExecutionFramework(solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths)
@ -282,3 +287,15 @@ bool ExecutionFramework::storageEmpty(h160 const& _addr) const
}
return true;
}
vector<solidity::frontend::test::LogRecord> ExecutionFramework::recordedLogs() const
{
vector<LogRecord> logs;
for (evmc::MockedHost::log_record const& logRecord: m_evmcHost->recorded_logs)
logs.emplace_back(
EVMHost::convertFromEVMC(logRecord.creator),
bytes{logRecord.data.begin(), logRecord.data.end()},
logRecord.topics | ranges::views::transform([](evmc::bytes32 _bytes) { return EVMHost::convertFromEVMC(_bytes); }) | ranges::to<vector>
);
return logs;
}

View File

@ -39,6 +39,11 @@
#include <boost/test/unit_test.hpp>
namespace solidity::frontend::test
{
struct LogRecord;
} // namespace solidity::frontend::test
namespace solidity::test
{
using rational = boost::rational<bigint>;
@ -247,6 +252,12 @@ public:
return m_sender;
}
size_t numLogs() const;
size_t numLogTopics(size_t _logIdx) const;
util::h256 logTopic(size_t _logIdx, size_t _topicIdx) const;
util::h160 logAddress(size_t _logIdx) const;
bytes logData(size_t _logIdx) const;
private:
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)
@ -278,11 +289,7 @@ protected:
bool storageEmpty(util::h160 const& _addr) const;
bool addressHasCode(util::h160 const& _addr) const;
size_t numLogs() const;
size_t numLogTopics(size_t _logIdx) const;
util::h256 logTopic(size_t _logIdx, size_t _topicIdx) const;
util::h160 logAddress(size_t _logIdx) const;
bytes logData(size_t _logIdx) const;
std::vector<frontend::test::LogRecord> recordedLogs() const;
langutil::EVMVersion m_evmVersion;
solidity::frontend::RevertStrings m_revertStrings = solidity::frontend::RevertStrings::Default;

View File

@ -178,9 +178,9 @@ map<string, Builtin> SemanticTest::makeBuiltins()
};
}
vector<SideEffectHook> SemanticTest::makeSideEffectHooks() const
{
using namespace std::placeholders;
return {
[](FunctionCall const& _call) -> vector<string>
{
@ -192,7 +192,111 @@ vector<SideEffectHook> SemanticTest::makeSideEffectHooks() const
return result;
}
return {};
}};
},
bind(&SemanticTest::eventSideEffectHook, this, _1)
};
}
string SemanticTest::formatEventParameter(optional<AnnotatedEventSignature> _signature, bool _indexed, size_t _index, bytes const& _data)
{
auto isPrintableASCII = [](bytes const& s)
{
bool zeroes = true;
for (auto c: s)
{
if (static_cast<unsigned>(c) != 0x00)
{
zeroes = false;
if (static_cast<unsigned>(c) <= 0x1f || static_cast<unsigned>(c) >= 0x7f)
return false;
} else
break;
}
return !zeroes;
};
ABIType abiType(ABIType::Type::Hex);
if (isPrintableASCII(_data))
abiType = ABIType(ABIType::Type::String);
if (_signature.has_value())
{
vector<string> const& types = _indexed ? _signature->indexedTypes : _signature->nonIndexedTypes;
if (_index < types.size())
{
if (types.at(_index) == "bool")
abiType = ABIType(ABIType::Type::Boolean);
}
}
return BytesUtils::formatBytes(_data, abiType);
}
vector<string> SemanticTest::eventSideEffectHook(FunctionCall const&) const
{
vector<string> sideEffects;
vector<LogRecord> recordedLogs = ExecutionFramework::recordedLogs();
for (LogRecord const& log: recordedLogs)
{
optional<AnnotatedEventSignature> eventSignature;
if (!log.topics.empty())
eventSignature = matchEvent(log.topics[0]);
stringstream sideEffect;
sideEffect << "emit ";
if (eventSignature.has_value())
sideEffect << eventSignature.value().signature;
else
sideEffect << "<anonymous>";
if (m_contractAddress != log.creator)
sideEffect << " from 0x" << log.creator;
vector<string> eventStrings;
size_t index{0};
for (h256 const& topic: log.topics)
{
if (!eventSignature.has_value() || index != 0)
eventStrings.push_back("#" + formatEventParameter(eventSignature, true, index, topic.asBytes()));
++index;
}
soltestAssert(log.data.size() % 32 == 0, "");
for (size_t index = 0; index < log.data.size() / 32; ++index)
{
auto begin = log.data.begin() + static_cast<long>(index * 32);
bytes const& data = bytes{begin, begin + 32};
eventStrings.emplace_back(formatEventParameter(eventSignature, false, index, data));
}
if (!eventStrings.empty())
sideEffect << ": ";
sideEffect << joinHumanReadable(eventStrings);
sideEffects.emplace_back(sideEffect.str());
}
return sideEffects;
}
optional<AnnotatedEventSignature> SemanticTest::matchEvent(util::h256 const& hash) const
{
optional<AnnotatedEventSignature> result;
for (string& contractName: m_compiler.contractNames())
{
ContractDefinition const& contract = m_compiler.contractDefinition(contractName);
for (EventDefinition const* event: contract.events())
{
FunctionTypePointer eventFunctionType = event->functionType(true);
if (!event->isAnonymous() && keccak256(eventFunctionType->externalSignature()) == hash)
{
AnnotatedEventSignature eventInfo;
eventInfo.signature = eventFunctionType->externalSignature();
for (auto const& param: event->parameters())
if (param->isIndexed())
eventInfo.indexedTypes.emplace_back(param->type()->toString(true));
else
eventInfo.nonIndexedTypes.emplace_back(param->type()->toString(true));
result = eventInfo;
}
}
}
return result;
}
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)

View File

@ -30,6 +30,13 @@
namespace solidity::frontend::test
{
struct AnnotatedEventSignature
{
std::string signature;
std::vector<std::string> indexedTypes;
std::vector<std::string> nonIndexedTypes;
};
/**
* Class that represents a semantic test (or end-to-end test) and allows running it as part of the
* boost unit test environment or isoltest. It reads the Solidity source and an additional comment
@ -82,6 +89,9 @@ private:
bool checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const;
std::map<std::string, Builtin> makeBuiltins();
std::vector<SideEffectHook> makeSideEffectHooks() const;
std::vector<std::string> eventSideEffectHook(FunctionCall const&) const;
std::optional<AnnotatedEventSignature> matchEvent(util::h256 const& hash) const;
static std::string formatEventParameter(std::optional<AnnotatedEventSignature> _signature, bool _indexed, size_t _index, bytes const& _data);
SourceMap m_sources;
std::size_t m_lineOffset;
std::vector<TestFunctionCall> m_tests;

View File

@ -1416,686 +1416,6 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws)
}
}
BOOST_AUTO_TEST_CASE(event)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id, bool _manually) public payable {
if (_manually) {
bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f;
uint value = msg.value;
address sender = msg.sender;
assembly {
mstore(0, value)
log3(0, 0x20, s, sender, _id)
}
} else {
emit Deposit(msg.sender, _id, msg.value);
}
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 value(18);
u256 id(0x1234);
for (bool manually: {true, false})
{
callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
}
)
}
BOOST_AUTO_TEST_CASE(event_emit)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 value(18);
u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
)
}
BOOST_AUTO_TEST_CASE(event_constructor)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
constructor() {
emit Deposit(msg.sender, bytes32("abc"), 7);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(7)));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(string{"abc"}, h256::FromBinary, h256::AlignLeft));
)
}
BOOST_AUTO_TEST_CASE(event_no_arguments)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit();
function deposit() public {
emit Deposit();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()")));
)
}
BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit)
{
char const* sourceCode = R"(
contract A {
event x();
}
contract B is A {
function f() public returns (uint) {
emit A.x();
return 1;
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
callContractFunction("f()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()")));
);
}
BOOST_AUTO_TEST_CASE(events_with_same_name)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit();
event Deposit(address _addr);
event Deposit(address _addr, uint _amount);
event Deposit(address _addr, bool _flag);
function deposit() public returns (uint) {
emit Deposit();
return 1;
}
function deposit(address _addr) public returns (uint) {
emit Deposit(_addr);
return 2;
}
function deposit(address _addr, uint _amount) public returns (uint) {
emit Deposit(_addr, _amount);
return 3;
}
function deposit(address _addr, bool _flag) public returns (uint) {
emit Deposit(_addr, _flag);
return 4;
}
}
)";
h160 const c_loggedAddress = m_contractAddress;
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()")));
ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(logData(0), encodeArgs(c_loggedAddress));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)")));
ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)")));
ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, false));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bool)")));
)
}
BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit)
{
char const* sourceCode = R"(
contract A {
event Deposit();
}
contract B {
event Deposit(address _addr);
}
contract ClientReceipt is A, B {
event Deposit(address _addr, uint _amount);
function deposit() public returns (uint) {
emit Deposit();
return 1;
}
function deposit(address _addr) public returns (uint) {
emit Deposit(_addr);
return 1;
}
function deposit(address _addr, uint _amount) public returns (uint) {
emit Deposit(_addr, _amount);
return 1;
}
}
)";
h160 const c_loggedAddress = m_contractAddress;
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()")));
ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(c_loggedAddress));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)")));
ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)")));
)
}
BOOST_AUTO_TEST_CASE(event_anonymous)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit() anonymous;
function deposit() public {
emit Deposit();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogTopics(0), 0);
)
}
BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous;
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value, 2, "abc");
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 value(18);
u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs("abc"));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 4);
BOOST_CHECK_EQUAL(logTopic(0, 0), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(id));
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(value));
BOOST_CHECK_EQUAL(logTopic(0, 3), h256(2));
)
}
BOOST_AUTO_TEST_CASE(event_lots_of_data)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address _from, bytes32 _id, uint _value, bool _flag);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value, true);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 value(18);
u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(m_sender, id, value, true));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256,bool)")));
)
}
BOOST_AUTO_TEST_CASE(event_really_lots_of_data)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
emit Deposit(10, msg.data, 15);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(util::keccak256("deposit()")).asBytes()))));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
{
char const* sourceCode = R"(
contract ClientReceipt {
bytes x;
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
x.push("A");
x.push("B");
x.push("C");
emit Deposit(10, x, 15);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC"))));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage)
{
char const* sourceCode = R"(
contract ClientReceipt {
bytes x;
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
x = new bytes(31);
x[0] = "A";
x[1] = "B";
x[2] = "C";
x[30] = "Z";
emit Deposit(10, x, 15);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z"));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(event_struct_memory_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
struct S { uint a; }
event E(S);
function createEvent(uint x) public {
emit E(S(x));
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(x));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))")));
}
BOOST_AUTO_TEST_CASE(event_struct_storage_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
struct S { uint a; }
event E(S);
S s;
function createEvent(uint x) public {
s.a = x;
emit E(s);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(x));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory)
{
char const* sourceCode = R"(
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
event E(uint[][]);
function createEvent(uint x) public {
uint[][] memory arr = new uint[][](2);
arr[0] = new uint[](2);
arr[1] = new uint[](2);
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_storage)
{
char const* sourceCode = R"(
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
while (arr.length < 3)
arr.push();
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])")));
)
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
while (arr.length < 3)
arr.push();
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])")));
)
}
BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2)
{
char const* sourceCode = R"(
pragma abicoder v2;
contract C {
event E(uint[][]);
uint[][] arr;
function createEvent(uint x) public {
arr.push(new uint[](2));
arr.push(new uint[](2));
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
)";
/// TODO enable again after push(..) via yul is implemented for nested arrays.
/// ALSO_VIA_YUL()
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])")));
}
BOOST_AUTO_TEST_CASE(event_indexed_string)
{
char const* sourceCode = R"(
contract C {
string x;
uint[4] y;
event E(string indexed r, uint[4] indexed t);
function deposit() public {
for (uint i = 0; i < 90; i++)
bytes(x).push(0);
for (uint8 i = 0; i < 90; i++)
bytes(x)[i] = bytes1(i);
y[0] = 4;
y[1] = 5;
y[2] = 6;
y[3] = 7;
emit E(x, y);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
string dynx(90, 0);
std::iota(dynx.begin(), dynx.end(), 0);
BOOST_CHECK(logData(0) == bytes());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(dynx));
BOOST_CHECK_EQUAL(logTopic(0, 2), util::keccak256(
encodeArgs(u256(4), u256(5), u256(6), u256(7))
));
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string,uint256[4])")));
}
BOOST_AUTO_TEST_CASE(event_indexed_function)
{
char const* sourceCode = R"(
contract C {
event Test(function() external indexed);
function f() public {
emit Test(this.f);
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
callContractFunction("f()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(logData(0) == bytes());
BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
bytes functionHash = util::keccak256("f()").asBytes();
bytes address = m_contractAddress.asBytes();
bytes selector = bytes(functionHash.cbegin(), functionHash.cbegin() + 4);
bytes padding = bytes(8, 0);
bytes functionABI = address + selector + padding;
BOOST_CHECK_EQUAL(logTopic(0, 1).hex(), util::toHex(functionABI));
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Test(function)")));
)
}
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
{
char const* sourceCode = R"(
@ -5292,37 +4612,6 @@ BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings)
)
}
BOOST_AUTO_TEST_CASE(event_signature_in_library)
{
// This tests a bug that was present where the "internal signature"
// for structs was also used for events.
char const* sourceCode = R"(
pragma abicoder v2;
library L {
struct S {
uint8 a;
int16 b;
}
event E(S indexed, S);
function f() internal {
S memory s;
emit E(s, s);
}
}
contract C {
constructor() {
L.f();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode, 0, "C");
BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16),(uint8,int16))")));
)
}
BOOST_AUTO_TEST_CASE(code_access)
{
char const* sourceCode = R"(

View File

@ -0,0 +1,23 @@
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id, bool _manually) public payable {
if (_manually) {
bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f;
uint value = msg.value;
address sender = msg.sender;
assembly {
mstore(0, value)
log3(0, 0x20, s, sender, _id)
}
} else {
emit Deposit(msg.sender, _id, msg.value);
}
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32,bool), 18 wei: 0x1234, true ->
// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12
// deposit(bytes32,bool), 18 wei: 0x1234, false ->
// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12

View File

@ -0,0 +1,14 @@
contract A {
event x();
}
contract B is A {
function f() public returns (uint) {
emit A.x();
return 1;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 1
// ~ emit x()

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit() anonymous;
function deposit() public {
emit Deposit();
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit <anonymous>

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(uint256 indexed _from, bytes32 indexed _id, uint _value) anonymous;
function deposit(bytes32 _id) public payable {
emit Deposit(0x2012159ca6b6372f102c535a4814d13a00bfc5568ddfd72151364061b00355d1, _id, msg.value); // 0x2012159c -> 'Deposit(uint256,bytes32,uint256)'
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit <anonymous>: #0x2012159ca6b6372f102c535a4814d13a00bfc5568ddfd72151364061b00355d1, #0x1234, 0x12

View File

@ -0,0 +1,12 @@
contract ClientReceipt {
event Withdraw(uint _value, string owner);
event Deposit(uint256 indexed _from, bytes32 indexed _id, uint _value) anonymous;
function deposit(bytes32 _id) public payable {
emit Deposit(0x5ddaa77ac5bda319ba947e31bee594711f39ed1b20d079d438dbad5ed729fb30, _id, msg.value); // 0x5ddaa77a -> 'Withdraw(uint256,string)'
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit Withdraw(uint256,string): #0x1234, 0x12

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous;
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value, 2, "abc");
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit <anonymous>: #0x1212121212121212121212121212120000000012, #0x1234, #0x12, #0x02, "abc"

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
constructor() {
emit Deposit(msg.sender, bytes32("abc"), 7);
}
}
// ====
// compileViaYul: also
// ----
// constructor()
// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #"abc", 0x07

View File

@ -0,0 +1,15 @@
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c

View File

@ -0,0 +1,16 @@
pragma abicoder v2;
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c

View File

@ -0,0 +1,20 @@
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
while (arr.length < 3)
arr.push();
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c
// gas irOptimized: 115211
// gas legacy: 116393
// gas legacyOptimized: 114415

View File

@ -0,0 +1,21 @@
pragma abicoder v2;
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
while (arr.length < 3)
arr.push();
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c
// gas irOptimized: 115211
// gas legacy: 116393
// gas legacyOptimized: 114415

View File

@ -0,0 +1,19 @@
pragma abicoder v2;
contract C {
event E(uint[][]);
function createEvent(uint x) public {
uint[][] memory arr = new uint[][](2);
arr[0] = new uint[](2);
arr[1] = new uint[](2);
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[][]): 0x20, 0x02, 0x40, 0xa0, 0x02, 0x2a, 0x2b, 0x02, 0x2c, 0x2d

View File

@ -0,0 +1,22 @@
pragma abicoder v2;
contract C {
event E(uint[][]);
uint[][] arr;
function createEvent(uint x) public {
arr.push(new uint[](2));
arr.push(new uint[](2));
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E(uint256[][]): 0x20, 0x02, 0x40, 0xa0, 0x02, 0x2a, 0x2b, 0x02, 0x2c, 0x2d
// gas irOptimized: 185905
// gas legacy: 187621
// gas legacyOptimized: 184551

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value);
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12

View File

@ -0,0 +1,22 @@
contract D {
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value);
}
}
contract C {
D d;
constructor() {
d = new D();
}
function deposit(bytes32 _id) public payable {
d.deposit(_id);
}
}
// ====
// compileViaYul: also
// ----
// constructor() ->
// gas legacy: 249112
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit Deposit(address,bytes32,uint256) from 0xf01f7809444bd9a93a854361c6fae3f23d9e23db: #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b, #0x1234, 0x00

View File

@ -0,0 +1,11 @@
contract C {
event Test(function() external indexed);
function f() public {
emit Test(this.f);
}
}
// ====
// compileViaYul: also
// ----
// f() ->
// ~ emit Test(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b26121ff00000000000000000

View File

@ -0,0 +1,17 @@
contract C {
event TestA(function() external indexed);
event TestB(function(uint256) external indexed);
function f1() public {
emit TestA(this.f1);
}
function f2(uint256 a) public {
emit TestB(this.f2);
}
}
// ====
// compileViaYul: also
// ----
// f1() ->
// ~ emit TestA(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bc27fc3050000000000000000
// f2(uint256): 1 ->
// ~ emit TestB(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bbf3724af0000000000000000

View File

@ -0,0 +1,24 @@
contract C {
string x;
uint[4] y;
event E(string indexed r, uint[4] indexed t);
function deposit() public {
for (uint i = 0; i < 90; i++)
bytes(x).push(0);
for (uint8 i = 0; i < 90; i++)
bytes(x)[i] = bytes1(i);
y[0] = 4;
y[1] = 5;
y[2] = 6;
y[3] = 7;
emit E(x, y);
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit E(string,uint256[4]): #0xa7fb06bb999a5eb9aff9e0779953f4e1e4ce58044936c2f51c7fb879b85c08bd, #0xe755d8cc1a8cde16a2a31160dcd8017ac32d7e2f13215b29a23cdae40a78aa81
// gas irOptimized: 368478
// gas legacy: 390742
// gas legacyOptimized: 376774

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(address _from, bytes32 _id, uint _value, bool _flag);
function deposit(bytes32 _id) public payable {
emit Deposit(msg.sender, _id, msg.value, true);
}
}
// ====
// compileViaYul: also
// ----
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit Deposit(address,bytes32,uint256,bool): 0x1212121212121212121212121212120000000012, 0x1234, 0x12, true

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit();
function deposit() public {
emit Deposit();
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit Deposit()

View File

@ -0,0 +1,11 @@
contract ClientReceipt {
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
emit Deposit(10, msg.data, 15);
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x04, 0xd0e30db000000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1,15 @@
contract ClientReceipt {
bytes x;
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
x.push("A");
x.push("B");
x.push("C");
emit Deposit(10, x, 15);
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x03, "ABC"

View File

@ -0,0 +1,17 @@
contract ClientReceipt {
bytes x;
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() public {
x = new bytes(31);
x[0] = "A";
x[1] = "B";
x[2] = "C";
x[30] = "Z";
emit Deposit(10, x, 15);
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x1f, "ABC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Z"

View File

@ -0,0 +1,23 @@
pragma abicoder v2;
library L {
struct S {
uint8 a;
int16 b;
}
event E(S indexed, S);
function f() internal {
S memory s;
emit E(s, s);
}
}
contract C {
constructor() {
L.f();
}
}
// ====
// compileViaYul: also
// ----
// constructor()
// ~ emit E((uint8,int16),(uint8,int16)): #0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5, 0x00, 0x00
// gas legacy: 150662

View File

@ -0,0 +1,11 @@
contract C {
event E(string r);
function deposit() public {
emit E("HELLO WORLD");
}
}
// ====
// compileViaYul: also
// ----
// deposit() ->
// ~ emit E(string): 0x20, 0x0b, "HELLO WORLD"

View File

@ -0,0 +1,13 @@
pragma abicoder v2;
contract C {
struct S { uint a; }
event E(S);
function createEvent(uint x) public {
emit E(S(x));
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E((uint256)): 0x2a

View File

@ -0,0 +1,15 @@
pragma abicoder v2;
contract C {
struct S { uint a; }
event E(S);
S s;
function createEvent(uint x) public {
s.a = x;
emit E(s);
}
}
// ====
// compileViaYul: also
// ----
// createEvent(uint256): 42 ->
// ~ emit E((uint256)): 0x2a

View File

@ -0,0 +1,33 @@
contract ClientReceipt {
event Deposit();
event Deposit(address _addr);
event Deposit(address _addr, uint _amount);
event Deposit(address _addr, bool _flag);
function deposit() public returns (uint) {
emit Deposit();
return 1;
}
function deposit(address _addr) public returns (uint) {
emit Deposit(_addr);
return 2;
}
function deposit(address _addr, uint _amount) public returns (uint) {
emit Deposit(_addr, _amount);
return 3;
}
function deposit(address _addr, bool _flag) public returns (uint) {
emit Deposit(_addr, _flag);
return 4;
}
}
// ====
// compileViaYul: also
// ----
// deposit() -> 1
// ~ emit Deposit()
// deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 -> 2
// ~ emit Deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988
// deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 100 -> 3
// ~ emit Deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 0x64
// deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false -> 4
// ~ emit Deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false

View File

@ -0,0 +1,32 @@
contract A {
event Deposit();
}
contract B {
event Deposit(address _addr);
}
contract ClientReceipt is A, B {
event Deposit(address _addr, uint _amount);
function deposit() public returns (uint) {
emit Deposit();
return 1;
}
function deposit(address _addr) public returns (uint) {
emit Deposit(_addr);
return 1;
}
function deposit(address _addr, uint _amount) public returns (uint) {
emit Deposit(_addr, _amount);
return 1;
}
}
// ====
// compileViaYul: also
// ----
// deposit() -> 1
// ~ emit Deposit()
// deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 -> 1
// ~ emit Deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988
// deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 100 -> 1
// ~ emit Deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 0x64

View File

@ -197,12 +197,14 @@ contract DepositContract is IDepositContract, ERC165 {
// gas legacyOptimized: 122798
// get_deposit_count() -> 0x20, 8, 0
// deposit(bytes,bytes,bytes,bytes32), 1 ether: 0x80, 0xe0, 0x120, 0xaa4a8d0b7d9077248630f1a4701ae9764e42271d7f22b7838778411857fd349e, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0x00f50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8 -> # txhash: 0x7085c586686d666e8bb6e9477a0f0b09565b2060a11f1c4209d3a52295033832 #
// ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0xf50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x08, 0xca9a3b00000000000000000000000000000000000000000000000000000000, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8, 0x08, 0x00
// get_deposit_root() -> 0x2089653123d9c721215120b6db6738ba273bbc5228ac093b1f983badcdc8a438
// gas irOptimized: 127486
// gas legacy: 150475
// gas legacyOptimized: 122811
// get_deposit_count() -> 0x20, 8, 0x0100000000000000000000000000000000000000000000000000000000000000
// deposit(bytes,bytes,bytes,bytes32), 32 ether: 0x80, 0xe0, 0x120, 0xdbd986dc85ceb382708cf90a3500f500f0a393c5ece76963ac3ed72eccd2c301, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x00344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d -> # txhash: 0x404d8e109822ce448e68f45216c12cb051b784d068fbe98317ab8e50c58304ac #
// ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x08, 0x40597307000000000000000000000000000000000000000000000000000000, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d, 0x08, 0x0100000000000000000000000000000000000000000000000000000000000000
// get_deposit_root() -> 0x40255975859377d912c53aa853245ebd939bdd2b33a28e084babdcc1ed8238ee
// gas irOptimized: 127486
// gas legacy: 150475

View File

@ -277,7 +277,7 @@ contract Test {
input[7] = 9643208548031422463313148630985736896287522941726746581856185889848792022807;
input[8] = 18066496933330839731877828156604;
if (verify(input, proof) == 0) {
emit Verified("Transaction successfully verified.");
emit Verified("Successfully verified.");
return true;
} else {
return false;
@ -296,6 +296,7 @@ contract Test {
// g() -> true
// pair() -> true
// verifyTx() -> true
// gas irOptimized: 111716
// gas legacy: 114371
// gas legacyOptimized: 83947
// ~ emit Verified(string): 0x20, 0x16, "Successfully verified."
// gas irOptimized: 111439
// gas legacy: 114094
// gas legacyOptimized: 83670

View File

@ -15,3 +15,4 @@ contract C {
// ----
// library: L
// f() ->
// ~ emit Ev((uint256)): 0x01

View File

@ -98,7 +98,10 @@ contract ERC20 {
// ----
// totalSupply() -> 20
// transfer(address,uint256): 2, 5 -> true
// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x05
// decreaseAllowance(address,uint256): 2, 0 -> true
// ~ emit Approval(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x00
// decreaseAllowance(address,uint256): 2, 1 -> FAILURE, hex"4e487b71", 0x11
// transfer(address,uint256): 2, 14 -> true
// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x0e
// transfer(address,uint256): 2, 2 -> FAILURE, hex"4e487b71", 0x11

View File

@ -19,6 +19,8 @@
#include <test/ExecutionFramework.h>
#include <utility>
namespace solidity::frontend::test
{
@ -311,4 +313,24 @@ struct FunctionCall
using Builtin = std::function<std::optional<bytes>(FunctionCall const&)>;
using SideEffectHook = std::function<std::vector<std::string>(FunctionCall const&)>;
struct LogRecord
{
util::h160 creator;
bytes data;
std::vector<util::h256> topics;
LogRecord(util::h160 _creator, bytes _data, std::vector<util::h256> _topics):
creator(std::move(_creator)), data(std::move(_data)), topics(std::move(_topics)) {}
bool operator==(LogRecord const& other) const noexcept
{
return creator == other.creator && data == other.data && topics == other.topics;
}
bool operator!=(LogRecord const& other) const noexcept
{
return !operator==(other);
}
};
}

View File

@ -196,8 +196,6 @@ string TestFunctionCall::format(
}
}
stream << formatGasExpectations(_linePrefix, _renderMode == RenderMode::ExpectedValuesActualGas, _interactivePrint);
vector<string> sideEffects;
if (_renderMode == RenderMode::ExpectedValuesExpectedGas || _renderMode == RenderMode::ExpectedValuesActualGas)
sideEffects = m_call.expectedSideEffects;
@ -214,6 +212,8 @@ string TestFunctionCall::format(
stream << std::endl;
}
}
stream << formatGasExpectations(_linePrefix, _renderMode == RenderMode::ExpectedValuesActualGas, _interactivePrint);
};
formatOutput(m_call.displayMode == FunctionCall::DisplayMode::SingleLine);