From 58f7a27ee0336423fa7dc76b8a160b78301bbdd2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 27 Jun 2017 10:25:36 +0100 Subject: Add sig member on function type --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 5 +++++ libsolidity/codegen/ExpressionCompiler.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index d3627565..49fbf8f1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.4.17 (unreleased) Features: + * Code Generator: Added ``.sig`` member on external function types to retrieve their signature. * Optimizer: Add new optimization step to remove unused ``JUMPDEST``s. * Type Checker: Display helpful warning for unused function arguments/return parameters. * Type Checker: Do not show the same error multiple times for events. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 10424858..5aa52383 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2436,6 +2436,11 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con case Kind::BareDelegateCall: { MemberList::MemberMap members; + if (m_kind == Kind::External) + members.push_back(MemberList::Member( + "sig", + make_shared(4) + )); if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall) { if (isPayable()) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5c9b743a..b7aadc12 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1068,7 +1068,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "Invalid member access to integer"); break; case Type::Category::Function: - solAssert(!!_memberAccess.expression().annotation().type->memberType(member), + if (member == "sig") + { + m_context << Instruction::SWAP1 << Instruction::POP; + /// need to store store it as bytes4 + utils().leftShiftNumberOnStack(224); + } + else + solAssert(!!_memberAccess.expression().annotation().type->memberType(member), "Invalid member access to function."); break; case Type::Category::Magic: -- cgit v1.2.3 From 88946f9f03625fab345572c66b33ee3e05a07159 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 27 Jun 2017 12:15:51 +0100 Subject: Add tests for function type sigs --- test/libsolidity/SolidityEndToEndTest.cpp | 24 +++++++ test/libsolidity/SolidityNameAndTypeResolution.cpp | 81 ++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 73dd7d22..f3d0fde3 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -10051,6 +10051,30 @@ BOOST_AUTO_TEST_CASE(delegatecall_return_value) BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1))); } +BOOST_AUTO_TEST_CASE(function_types_sig) +{ + char const* sourceCode = R"( + contract C { + function f() returns (bytes4) { + return this.f.sig; + } + function g() returns (bytes4) { + function () external returns (bytes4) fun = this.f; + return fun.sig; + } + function h() returns (bytes4) { + function () external returns (bytes4) fun = this.f; + var funvar = fun; + return funvar.sig; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == fromHex("0x26121ff0")); + BOOST_CHECK(callContractFunction("g()") == fromHex("0x26121ff0")); + BOOST_CHECK(callContractFunction("h()") == fromHex("0x26121ff0")); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 1fbc55a2..6576634f 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -6285,6 +6285,87 @@ BOOST_AUTO_TEST_CASE(modifiers_access_storage_pointer) CHECK_SUCCESS_NO_WARNINGS(text); } +BOOST_AUTO_TEST_CASE(function_types_sig) +{ + char const* text = R"( + contract C { + function f() returns (bytes4) { + return f.sig; + } + } + )"; + CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + text = R"( + contract C { + function g() internal { + } + function f() returns (bytes4) { + return g.sig; + } + } + )"; + CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + text = R"( + contract C { + function f() returns (bytes4) { + function () g; + return g.sig; + } + } + )"; + CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + text = R"( + contract C { + function f() returns (bytes4) { + return this.f.sig; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( + contract C { + function f() external returns (bytes4) { + return this.f.sig; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( + contract C { + function h() external { + } + function f() external returns (bytes4) { + var g = this.h; + return g.sig; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( + contract C { + function h() external { + } + function f() external returns (bytes4) { + function () external g = this.h; + return g.sig; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( + contract C { + function h() external { + } + function f() external returns (bytes4) { + function () external g = this.h; + var i = g; + return i.sig; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + BOOST_AUTO_TEST_CASE(using_this_in_constructor) { char const* text = R"( -- cgit v1.2.3 From fd1f8ab38ba7f2bb04e67a44ea5e947eddcf9b13 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 28 Jun 2017 18:15:41 +0100 Subject: Rename .sig to .selector on function types --- Changelog.md | 2 +- libsolidity/ast/Types.cpp | 2 +- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 6 +++--- test/libsolidity/SolidityNameAndTypeResolution.cpp | 22 +++++++++++----------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Changelog.md b/Changelog.md index 49fbf8f1..d90cd3f6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,7 @@ ### 0.4.17 (unreleased) Features: - * Code Generator: Added ``.sig`` member on external function types to retrieve their signature. + * Code Generator: Added ``.selector`` member on external function types to retrieve their signature. * Optimizer: Add new optimization step to remove unused ``JUMPDEST``s. * Type Checker: Display helpful warning for unused function arguments/return parameters. * Type Checker: Do not show the same error multiple times for events. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 5aa52383..705d0f7f 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2438,7 +2438,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con MemberList::MemberMap members; if (m_kind == Kind::External) members.push_back(MemberList::Member( - "sig", + "selector", make_shared(4) )); if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index b7aadc12..631a25ff 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1068,7 +1068,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "Invalid member access to integer"); break; case Type::Category::Function: - if (member == "sig") + if (member == "selector") { m_context << Instruction::SWAP1 << Instruction::POP; /// need to store store it as bytes4 diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f3d0fde3..661d184a 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -10056,16 +10056,16 @@ BOOST_AUTO_TEST_CASE(function_types_sig) char const* sourceCode = R"( contract C { function f() returns (bytes4) { - return this.f.sig; + return this.f.selector; } function g() returns (bytes4) { function () external returns (bytes4) fun = this.f; - return fun.sig; + return fun.selector; } function h() returns (bytes4) { function () external returns (bytes4) fun = this.f; var funvar = fun; - return funvar.sig; + return funvar.selector; } } )"; diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 6576634f..9f33c5b3 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -6290,34 +6290,34 @@ BOOST_AUTO_TEST_CASE(function_types_sig) char const* text = R"( contract C { function f() returns (bytes4) { - return f.sig; + return f.selector; } } )"; - CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + CHECK_ERROR(text, TypeError, "Member \"selector\" not found"); text = R"( contract C { function g() internal { } function f() returns (bytes4) { - return g.sig; + return g.selector; } } )"; - CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + CHECK_ERROR(text, TypeError, "Member \"selector\" not found"); text = R"( contract C { function f() returns (bytes4) { function () g; - return g.sig; + return g.selector; } } )"; - CHECK_ERROR(text, TypeError, "Member \"sig\" not found"); + CHECK_ERROR(text, TypeError, "Member \"selector\" not found"); text = R"( contract C { function f() returns (bytes4) { - return this.f.sig; + return this.f.selector; } } )"; @@ -6325,7 +6325,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig) text = R"( contract C { function f() external returns (bytes4) { - return this.f.sig; + return this.f.selector; } } )"; @@ -6336,7 +6336,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig) } function f() external returns (bytes4) { var g = this.h; - return g.sig; + return g.selector; } } )"; @@ -6347,7 +6347,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig) } function f() external returns (bytes4) { function () external g = this.h; - return g.sig; + return g.selector; } } )"; @@ -6359,7 +6359,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig) function f() external returns (bytes4) { function () external g = this.h; var i = g; - return i.sig; + return i.selector; } } )"; -- cgit v1.2.3 From c70ebfd241cc3dc6d19847d94b11784da1c79cdd Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 11 Jul 2017 18:10:42 +0100 Subject: Document function selectors --- docs/abi-spec.rst | 2 ++ docs/types.rst | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index fc1a3adb..3ce7f50c 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -17,6 +17,8 @@ We assume the interface functions of a contract are strongly typed, known at com This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. Should these cases become important they can be adequately handled as facilities built within the Ethereum ecosystem. +.. _abi_function_selector: + Function Selector ================= diff --git a/docs/types.rst b/docs/types.rst index 3335655a..5c291f35 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -400,6 +400,17 @@ Note that public functions of the current contract can be used both as an internal and as an external function. To use ``f`` as an internal function, just use ``f``, if you want to use its external form, use ``this.f``. +Additionally, public (or external) functions also have a special member called ``selector``, +which returns the :ref:`ABI function selector `:: + + pragma solidity ^0.4.0; + + contract Selector { + function f() returns (bytes4) { + return this.f.selector; + } + } + Example that shows how to use internal function types:: pragma solidity ^0.4.5; -- cgit v1.2.3 From 8b166c36369d0d1b39a4c537bc6ee8a08f3c6e5a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 11 Jul 2017 20:22:08 +0100 Subject: Use hashing function in tests --- test/libsolidity/SolidityEndToEndTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 661d184a..1a2abea3 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -10070,9 +10070,9 @@ BOOST_AUTO_TEST_CASE(function_types_sig) } )"; compileAndRun(sourceCode, 0, "C"); - BOOST_CHECK(callContractFunction("f()") == fromHex("0x26121ff0")); - BOOST_CHECK(callContractFunction("g()") == fromHex("0x26121ff0")); - BOOST_CHECK(callContractFunction("h()") == fromHex("0x26121ff0")); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes()))); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes()))); + BOOST_CHECK(callContractFunction("h()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes()))); } BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.3