mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12548 from joshieDo/other-signatures
Add event and error identifiers to --hashes
This commit is contained in:
commit
5539a745df
@ -6,6 +6,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler 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 Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value.
|
||||||
* Yul: Emit immutable references for pure yul code when requested.
|
* Yul: Emit immutable references for pure yul code when requested.
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ FunctionDefinition const* ContractDefinition::receiveFunction() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() const
|
vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents() const
|
||||||
{
|
{
|
||||||
return m_interfaceEvents.init([&]{
|
return m_interfaceEvents.init([&]{
|
||||||
set<string> eventsSeen;
|
set<string> eventsSeen;
|
||||||
@ -213,11 +213,20 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
|
|||||||
interfaceEvents.push_back(e);
|
interfaceEvents.push_back(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return interfaceEvents;
|
return interfaceEvents;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const
|
||||||
|
{
|
||||||
|
solAssert(annotation().creationCallGraph.set(), "");
|
||||||
|
|
||||||
|
return convertContainer<std::vector<EventDefinition const*>>(
|
||||||
|
(*annotation().creationCallGraph)->emittedEvents +
|
||||||
|
(*annotation().deployedCallGraph)->emittedEvents
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
|
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
|
||||||
{
|
{
|
||||||
set<ErrorDefinition const*, CompareByID> result;
|
set<ErrorDefinition const*, CompareByID> result;
|
||||||
@ -227,10 +236,9 @@ vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _require
|
|||||||
if (_requireCallGraph)
|
if (_requireCallGraph)
|
||||||
solAssert(annotation().creationCallGraph.set(), "");
|
solAssert(annotation().creationCallGraph.set(), "");
|
||||||
if (annotation().creationCallGraph.set())
|
if (annotation().creationCallGraph.set())
|
||||||
{
|
result +=
|
||||||
result += (*annotation().creationCallGraph)->usedErrors;
|
(*annotation().creationCallGraph)->usedErrors +
|
||||||
result += (*annotation().deployedCallGraph)->usedErrors;
|
(*annotation().deployedCallGraph)->usedErrors;
|
||||||
}
|
|
||||||
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +519,8 @@ public:
|
|||||||
return ranges::subrange<decltype(b)>(b, e) | ranges::views::values;
|
return ranges::subrange<decltype(b)>(b, e) | ranges::views::values;
|
||||||
}
|
}
|
||||||
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
|
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
|
||||||
std::vector<EventDefinition const*> const& interfaceEvents() const;
|
std::vector<EventDefinition const*> const& definedInterfaceEvents() const;
|
||||||
|
std::vector<EventDefinition const*> const usedInterfaceEvents() const;
|
||||||
/// @returns all errors defined in this contract or any base contract
|
/// @returns all errors defined in this contract or any base contract
|
||||||
/// and all errors referenced during execution.
|
/// and all errors referenced during execution.
|
||||||
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
|
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
|
||||||
|
@ -101,7 +101,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
|
|||||||
method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability());
|
method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability());
|
||||||
abi.emplace(std::move(method));
|
abi.emplace(std::move(method));
|
||||||
}
|
}
|
||||||
for (auto const& it: _contractDef.interfaceEvents())
|
for (auto const& it: _contractDef.definedInterfaceEvents())
|
||||||
{
|
{
|
||||||
Json::Value event{Json::objectValue};
|
Json::Value event{Json::objectValue};
|
||||||
event["type"] = "event";
|
event["type"] = "event";
|
||||||
|
@ -75,11 +75,14 @@
|
|||||||
#include <libsolutil/IpfsHash.h>
|
#include <libsolutil/IpfsHash.h>
|
||||||
#include <libsolutil/JSON.h>
|
#include <libsolutil/JSON.h>
|
||||||
#include <libsolutil/Algorithms.h>
|
#include <libsolutil/Algorithms.h>
|
||||||
|
#include <libsolutil/FunctionSelector.h>
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
|
#include <range/v3/view/concat.hpp>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@ -1013,15 +1016,34 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
|
|||||||
return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
|
return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
|
Json::Value CompilerStack::interfaceSymbols(string const& _contractName) const
|
||||||
{
|
{
|
||||||
if (m_stackState < AnalysisPerformed)
|
if (m_stackState < AnalysisPerformed)
|
||||||
solThrow(CompilerError, "Analysis was not successful.");
|
solThrow(CompilerError, "Analysis was not successful.");
|
||||||
|
|
||||||
Json::Value methodIdentifiers(Json::objectValue);
|
Json::Value interfaceSymbols(Json::objectValue);
|
||||||
|
// Always have a methods object
|
||||||
|
interfaceSymbols["methods"] = Json::objectValue;
|
||||||
|
|
||||||
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
|
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
|
||||||
methodIdentifiers[it.second->externalSignature()] = it.first.hex();
|
interfaceSymbols["methods"][it.second->externalSignature()] = it.first.hex();
|
||||||
return methodIdentifiers;
|
for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors())
|
||||||
|
{
|
||||||
|
string signature = error->functionType(true)->externalSignature();
|
||||||
|
interfaceSymbols["errors"][signature] = toHex(toCompactBigEndian(selectorFromSignature32(signature), 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (EventDefinition const* event: ranges::concat_view(
|
||||||
|
contractDefinition(_contractName).definedInterfaceEvents(),
|
||||||
|
contractDefinition(_contractName).usedInterfaceEvents()
|
||||||
|
))
|
||||||
|
if (!event->isAnonymous())
|
||||||
|
{
|
||||||
|
string signature = event->functionType(true)->externalSignature();
|
||||||
|
interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(keccak256(signature))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaceSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const
|
bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const
|
||||||
|
@ -327,8 +327,8 @@ public:
|
|||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
Json::Value const& natspecDev(std::string const& _contractName) const;
|
Json::Value const& natspecDev(std::string const& _contractName) const;
|
||||||
|
|
||||||
/// @returns a JSON representing a map of method identifiers (hashes) to function names.
|
/// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names.
|
||||||
Json::Value methodIdentifiers(std::string const& _contractName) const;
|
Json::Value interfaceSymbols(std::string const& _contractName) const;
|
||||||
|
|
||||||
/// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
|
/// @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)); }
|
std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }
|
||||||
|
@ -78,7 +78,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
doc["methods"][it.second->externalSignature()]["notice"] = value;
|
doc["methods"][it.second->externalSignature()]["notice"] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& event: _contractDef.interfaceEvents())
|
for (auto const& event: _contractDef.definedInterfaceEvents())
|
||||||
{
|
{
|
||||||
string value = extractDoc(event->annotation().docTags, "notice");
|
string value = extractDoc(event->annotation().docTags, "notice");
|
||||||
if (!value.empty())
|
if (!value.empty())
|
||||||
|
@ -1298,7 +1298,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
|||||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly", wildcardMatchesExperimental))
|
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly", wildcardMatchesExperimental))
|
||||||
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName);
|
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName);
|
||||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers", wildcardMatchesExperimental))
|
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers", wildcardMatchesExperimental))
|
||||||
evmData["methodIdentifiers"] = compilerStack.methodIdentifiers(contractName);
|
evmData["methodIdentifiers"] = compilerStack.interfaceSymbols(contractName)["methods"];
|
||||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesExperimental))
|
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesExperimental))
|
||||||
evmData["gasEstimates"] = compilerStack.gasEstimates(contractName);
|
evmData["gasEstimates"] = compilerStack.gasEstimates(contractName);
|
||||||
|
|
||||||
|
@ -270,15 +270,29 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract)
|
|||||||
if (!m_options.compiler.outputs.signatureHashes)
|
if (!m_options.compiler.outputs.signatureHashes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Json::Value methodIdentifiers = m_compiler->methodIdentifiers(_contract);
|
Json::Value interfaceSymbols = m_compiler->interfaceSymbols(_contract);
|
||||||
string out;
|
string out = "Function signatures:\n";
|
||||||
for (auto const& name: methodIdentifiers.getMemberNames())
|
for (auto const& name: interfaceSymbols["methods"].getMemberNames())
|
||||||
out += methodIdentifiers[name].asString() + ": " + name + "\n";
|
out += interfaceSymbols["methods"][name].asString() + ": " + name + "\n";
|
||||||
|
|
||||||
|
if (interfaceSymbols.isMember("errors"))
|
||||||
|
{
|
||||||
|
out += "\nError signatures:\n";
|
||||||
|
for (auto const& name: interfaceSymbols["errors"].getMemberNames())
|
||||||
|
out += interfaceSymbols["errors"][name].asString() + ": " + name + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interfaceSymbols.isMember("events"))
|
||||||
|
{
|
||||||
|
out += "\nEvent signatures:\n";
|
||||||
|
for (auto const& name: interfaceSymbols["events"].getMemberNames())
|
||||||
|
out += interfaceSymbols["events"][name].asString() + ": " + name + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_options.output.dir.empty())
|
if (!m_options.output.dir.empty())
|
||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out);
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out);
|
||||||
else
|
else
|
||||||
sout() << "Function signatures:" << endl << out;
|
sout() << out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::handleMetadata(string const& _contract)
|
void CommandLineInterface::handleMetadata(string const& _contract)
|
||||||
@ -822,7 +836,7 @@ void CommandLineInterface::handleCombinedJSON()
|
|||||||
m_compiler->runtimeObject(contractName).functionDebugData
|
m_compiler->runtimeObject(contractName).functionDebugData
|
||||||
);
|
);
|
||||||
if (m_options.compiler.combinedJsonRequests->signatureHashes)
|
if (m_options.compiler.combinedJsonRequests->signatureHashes)
|
||||||
contractData[g_strSignatureHashes] = m_compiler->methodIdentifiers(contractName);
|
contractData[g_strSignatureHashes] = m_compiler->interfaceSymbols(contractName)["methods"];
|
||||||
if (m_options.compiler.combinedJsonRequests->natspecDev)
|
if (m_options.compiler.combinedJsonRequests->natspecDev)
|
||||||
contractData[g_strNatspecDev] = m_compiler->natspecDev(contractName);
|
contractData[g_strNatspecDev] = m_compiler->natspecDev(contractName);
|
||||||
if (m_options.compiler.combinedJsonRequests->natspecUser)
|
if (m_options.compiler.combinedJsonRequests->natspecUser)
|
||||||
|
1
test/cmdlineTests/hashes/args
Normal file
1
test/cmdlineTests/hashes/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--hashes
|
28
test/cmdlineTests/hashes/input.sol
Normal file
28
test/cmdlineTests/hashes/input.sol
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
24
test/cmdlineTests/hashes/output
Normal file
24
test/cmdlineTests/hashes/output
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
======= 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)
|
||||||
|
81f3fb02f88d32d3bb08c80c9a622ca3b3223292f131c6ad049811f9a8a606dc: libraryEvent(uint256)
|
||||||
|
|
||||||
|
======= hashes/input.sol:L =======
|
||||||
|
Function signatures:
|
||||||
|
|
||||||
|
Error signatures:
|
||||||
|
8c41f45c: libraryError(uint256)
|
||||||
|
c61c03f5: libraryErrorUnused(uint256)
|
||||||
|
|
||||||
|
Event signatures:
|
||||||
|
81f3fb02f88d32d3bb08c80c9a622ca3b3223292f131c6ad049811f9a8a606dc: libraryEvent(uint256)
|
||||||
|
0a994ad3600197f16ffe1ea1101caea3174efe5ebd9ba9a75d6d5524c5de28cd: libraryEventUnused(uint256)
|
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources":
|
||||||
|
{
|
||||||
|
"A":
|
||||||
|
{
|
||||||
|
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings":
|
||||||
|
{
|
||||||
|
"outputSelection":
|
||||||
|
{
|
||||||
|
"*": { "*": ["evm.methodIdentifiers"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
{"contracts":{"A":{"C":{"evm":{"methodIdentifiers":{}}}}},"sources":{"A":{"id":0}}}
|
@ -435,7 +435,7 @@ TestCase::TestResult SemanticTest::runTest(
|
|||||||
{
|
{
|
||||||
soltestAssert(
|
soltestAssert(
|
||||||
m_allowNonExistingFunctions ||
|
m_allowNonExistingFunctions ||
|
||||||
m_compiler.methodIdentifiers(m_compiler.lastContractName(m_sources.mainSourceFile)).isMember(test.call().signature),
|
m_compiler.interfaceSymbols(m_compiler.lastContractName(m_sources.mainSourceFile))["methods"].isMember(test.call().signature),
|
||||||
"The function " + test.call().signature + " is not known to the compiler"
|
"The function " + test.call().signature + " is not known to the compiler"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ optional<CompilerOutput> SolidityCompilationFramework::compileContract()
|
|||||||
else
|
else
|
||||||
contractName = m_compilerInput.contractName;
|
contractName = m_compilerInput.contractName;
|
||||||
evmasm::LinkerObject obj = m_compiler.object(contractName);
|
evmasm::LinkerObject obj = m_compiler.object(contractName);
|
||||||
Json::Value methodIdentifiers = m_compiler.methodIdentifiers(contractName);
|
Json::Value methodIdentifiers = m_compiler.interfaceSymbols(contractName)["methods"];
|
||||||
return CompilerOutput{obj.bytecode, methodIdentifiers};
|
return CompilerOutput{obj.bytecode, methodIdentifiers};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
/// @returns method identifiers in contract called @param _contractName.
|
/// @returns method identifiers in contract called @param _contractName.
|
||||||
Json::Value methodIdentifiers(std::string const& _contractName)
|
Json::Value methodIdentifiers(std::string const& _contractName)
|
||||||
{
|
{
|
||||||
return m_compiler.methodIdentifiers(_contractName);
|
return m_compiler.interfaceSymbols(_contractName)["methods"];
|
||||||
}
|
}
|
||||||
/// @returns Compilation output comprising EVM bytecode and list of
|
/// @returns Compilation output comprising EVM bytecode and list of
|
||||||
/// method identifiers in contract if compilation is successful,
|
/// method identifiers in contract if compilation is successful,
|
||||||
|
Loading…
Reference in New Issue
Block a user