diff --git a/Changelog.md b/Changelog.md index c938c44b0..98515970f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Language Features: Compiler Features: + * Commandline Interface: Event and error signatures are also returned when using ``--hashes``. * Yul Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value. * Yul: Emit immutable references for pure yul code when requested. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 5292d5329..a1c26ab37 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -75,6 +75,7 @@ #include #include #include +#include #include @@ -1024,6 +1025,37 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const return methodIdentifiers; } +Json::Value CompilerStack::errorIdentifiers(string const& _contractName) const +{ + if (m_stackState < AnalysisPerformed) + solThrow(CompilerError, "Analysis was not successful."); + + Json::Value errorIdentifiers(Json::objectValue); + for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors()) + { + string signature = error->functionType(true)->externalSignature(); + errorIdentifiers[signature] = toHex(toCompactBigEndian(selectorFromSignature32(signature), 4)); + } + + return errorIdentifiers; +} + +Json::Value CompilerStack::eventIdentifiers(string const& _contractName) const +{ + if (m_stackState < AnalysisPerformed) + solThrow(CompilerError, "Analysis was not successful."); + + Json::Value eventIdentifiers(Json::objectValue); + for (EventDefinition const* event: contractDefinition(_contractName).interfaceEvents()) + if (!event->isAnonymous()) + { + string signature = event->functionType(true)->externalSignature(); + eventIdentifiers[signature] = toHex(u256(h256::Arith(keccak256(signature)))); + } + + return eventIdentifiers; +} + bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const { if (m_stackState < AnalysisPerformed) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 3609662e0..2e1e687f7 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -330,6 +330,12 @@ public: /// @returns a JSON representing a map of method identifiers (hashes) to function names. Json::Value methodIdentifiers(std::string const& _contractName) const; + /// @returns a JSON representing a map of error identifiers (hashes) to error names. + Json::Value errorIdentifiers(std::string const& _contractName) const; + + /// @returns a JSON representing a map of event identifiers (hashes) to event names. + Json::Value eventIdentifiers(std::string const& _contractName) const; + /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting. std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 235059a02..d96460fa1 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -271,14 +271,30 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract) return; Json::Value methodIdentifiers = m_compiler->methodIdentifiers(_contract); - string out; + string out = "Function signatures:\n"; for (auto const& name: methodIdentifiers.getMemberNames()) out += methodIdentifiers[name].asString() + ": " + name + "\n"; + Json::Value errorIdentifiers = m_compiler->errorIdentifiers(_contract); + if (!errorIdentifiers.empty()) + { + out += "\nError signatures:\n"; + for (auto const& name: errorIdentifiers.getMemberNames()) + out += errorIdentifiers[name].asString() + ": " + name + "\n"; + } + + Json::Value eventIdentifiers = m_compiler->eventIdentifiers(_contract); + if (!eventIdentifiers.empty()) + { + out += "\nEvent signatures:\n"; + for (auto const& name: eventIdentifiers.getMemberNames()) + out += eventIdentifiers[name].asString() + ": " + name + "\n"; + } + if (!m_options.output.dir.empty()) createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out); else - sout() << "Function signatures:" << endl << out; + sout() << out; } void CommandLineInterface::handleMetadata(string const& _contract) diff --git a/test/cmdlineTests/hashes/args b/test/cmdlineTests/hashes/args new file mode 100644 index 000000000..40469d358 --- /dev/null +++ b/test/cmdlineTests/hashes/args @@ -0,0 +1 @@ +--hashes \ No newline at end of file diff --git a/test/cmdlineTests/hashes/input.sol b/test/cmdlineTests/hashes/input.sol new file mode 100644 index 000000000..1f5c758f7 --- /dev/null +++ b/test/cmdlineTests/hashes/input.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +error fileLevelError(uint z); + +library L { + event libraryEvent(uint r); + error libraryError(uint r); + error libraryErrorUnused(uint u); + event libraryEventUnused(uint u); +} + +contract C { + struct S { uint x; } + + event ev(uint y); + event anon_ev(uint y) anonymous; + + error err(uint z, uint w); + + function f(S memory s) public { + emit L.libraryEvent(3); + if (s.x > 1) + revert fileLevelError(3); + else + revert L.libraryError(4); + } +} diff --git a/test/cmdlineTests/hashes/output b/test/cmdlineTests/hashes/output new file mode 100644 index 000000000..5223d732a --- /dev/null +++ b/test/cmdlineTests/hashes/output @@ -0,0 +1,23 @@ + +======= hashes/input.sol:C ======= +Function signatures: +3fc03eeb: f((uint256)) + +Error signatures: +619a0bb7: err(uint256,uint256) +82b5f64f: fileLevelError(uint256) +8c41f45c: libraryError(uint256) + +Event signatures: +2d4dd5fe18ada5a020a9f5591539a8dc3010a5c074ba6a70e1c956659f02786a: ev(uint256) + +======= hashes/input.sol:L ======= +Function signatures: + +Error signatures: +8c41f45c: libraryError(uint256) +c61c03f5: libraryErrorUnused(uint256) + +Event signatures: +81f3fb02f88d32d3bb08c80c9a622ca3b3223292f131c6ad049811f9a8a606dc: libraryEvent(uint256) +0a994ad3600197f16ffe1ea1101caea3174efe5ebd9ba9a75d6d5524c5de28cd: libraryEventUnused(uint256)