Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export all events #10996

Merged
merged 1 commit into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Compiler Features:
* EVM: Support for the EVM Version "Shanghai".
* NatSpec: Add support for NatSpec documentation in ``enum`` definitions.
* NatSpec: Add support for NatSpec documentation in ``struct`` definitions.
* NatSpec: Include NatSpec from events that are emitted by a contract but defined outside of it in userdoc and devdoc output.
* Optimizer: Re-implement simplified version of UnusedAssignEliminator and UnusedStoreEliminator. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version.
* Parser: Unary plus is no longer recognized as a unary operator in the AST and triggers an error at the parsing stage (rather than later during the analysis).
* SMTChecker: Properties that are proved safe are now reported explicitly at the end of the analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties.
Expand All @@ -16,20 +17,22 @@ Compiler Features:


Bugfixes:
* ABI: Include events in the ABI that are emitted by a contract but defined outside of it.
* Antlr Grammar: Fix discrepancy with the parser, which allowed octal numbers.
* Antlr Grammar: Fix of a discrepancy with the parser, which allowed numbers followed by an identifier with no whitespace.
* Antlr Grammar: Stricter rules for function definitions. The grammar will no longer accept as valid free functions having specifiers which are exclusive to contract functions.
* SMTChecker: Fix false positives in ternary operators that contain verification targets in its branches, directly or indirectly.


AST Changes:
* AST: add the ``internalFunctionID`` field to the AST nodes of functions that may be called via the internal dispatch. These IDs are always generated, but they are only used in via-IR code generation.
* AST: Add the ``internalFunctionID`` field to the AST nodes of functions that may be called via the internal dispatch. These IDs are always generated, but they are only used in via-IR code generation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this line showing up in the diff by the way? Not sure if I'm blind, but I don't see any change in it...

Copy link
Collaborator

@matheusaaguiar matheusaaguiar May 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capitalized A in Add at the beginning of the sentence... had to look a dozen of times to spot it :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, lol - but that's also a bug in github - it usually highlights the actual change, here it doesn't :-)

* AST: Add the ``usedEvents`` field to ``ContractDefinition`` which contains the AST IDs of all events emitted by the contract as well as all events defined and inherited by the contract.


### 0.8.19 (2023-02-22)

Language Features:
* Allow defining custom operators for user-defined value types via ``using {f as +} for T global`` syntax.
* Allow defining custom operators for user-defined value types via ``using {f as +} for T global`` syntax.


Compiler Features:
Expand Down
21 changes: 18 additions & 3 deletions libsolidity/ast/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents
/// NOTE: this requires the "internal" version of an Event,
/// though here internal strictly refers to visibility,
/// and not to function encoding (jump vs. call)
auto const& function = e->functionType(true);
solAssert(function, "");
string eventSignature = function->externalSignature();
FunctionType const* functionType = e->functionType(true);
solAssert(functionType, "");
string eventSignature = functionType->externalSignature();
if (eventsSeen.count(eventSignature) == 0)
{
eventsSeen.insert(eventSignature);
Expand All @@ -243,6 +243,21 @@ vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() c
);
}

vector<EventDefinition const*> ContractDefinition::interfaceEvents(bool _requireCallGraph) const
{
set<EventDefinition const*, CompareByID> result;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
result += contract->events();
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set());
if (_requireCallGraph)
solAssert(annotation().creationCallGraph.set());
if (annotation().creationCallGraph.set())
result += usedInterfaceEvents();
// We could filter out all events that do not have an external interface
// if _requireCallGraph is false.
Comment on lines +256 to +257
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. My best guess is that it refers to events that are not a part of the external interface of the contract. Is that correct?

BTW, is this a TODO note? If so, any reason not to do this right away?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was meant to filter out events whose arguments have types that are not valid in an external interface. Maybe I was thinking about errors at that point? Because for events this is not really possible while for errors it might.

return util::convertContainer<vector<EventDefinition const*>>(std::move(result));
}

vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
{
set<ErrorDefinition const*, CompareByID> result;
Expand Down
4 changes: 4 additions & 0 deletions libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,10 @@ class ContractDefinition: public Declaration, public StructurallyDocumented, pub
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
std::vector<EventDefinition const*> const& definedInterfaceEvents() const;
std::vector<EventDefinition const*> const usedInterfaceEvents() const;
/// @return all events defined in this contract and its base contracts and all events
/// that are emitted during the execution of the contract.
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
std::vector<EventDefinition const*> interfaceEvents(bool _requireCallGraph = true) const;
/// @returns all errors defined in this contract or any base contract
/// and all errors referenced during execution.
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
Expand Down
2 changes: 2 additions & 0 deletions libsolidity/ast/ASTJsonExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ bool ASTJsonExporter::visit(ContractDefinition const& _node)
make_pair("abstract", _node.abstract()),
make_pair("baseContracts", toJson(_node.baseContracts())),
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)),
// Do not require call graph because the AST is also created for incorrect sources.
make_pair("usedEvents", getContainerIds(_node.interfaceEvents(false))),
make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))),
make_pair("nodes", toJson(_node.subNodes())),
make_pair("scope", idOrNull(_node.scope()))
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/interface/ABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability());
abi.emplace(std::move(method));
}
for (auto const& it: _contractDef.definedInterfaceEvents())
for (auto const& it: _contractDef.interfaceEvents())
{
Json::Value event{Json::objectValue};
event["type"] = "event";
Expand Down
53 changes: 50 additions & 3 deletions libsolidity/interface/Natspec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,16 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
doc["methods"][it.second->externalSignature()]["notice"] = value;
}

for (auto const& event: _contractDef.definedInterfaceEvents())
for (auto const& event: uniqueInterfaceEvents(_contractDef))
{
ContractDefinition const* eventOrigin = event->annotation().contract;
solAssert(eventOrigin);
solAssert(
*eventOrigin == _contractDef ||
(!eventOrigin->isLibrary() && _contractDef.derivesFrom(*eventOrigin)) ||
(eventOrigin->isLibrary() && !_contractDef.derivesFrom(*eventOrigin))
);

string value = extractDoc(event->annotation().docTags, "notice");
if (!value.empty())
doc["events"][event->functionType(true)->externalSignature()]["notice"] = value;
Expand Down Expand Up @@ -168,10 +176,18 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
));
}

for (auto const& event: _contractDef.definedInterfaceEvents())
for (auto const& event: uniqueInterfaceEvents(_contractDef))
if (auto devDoc = devDocumentation(event->annotation().docTags); !devDoc.empty())
{
ContractDefinition const* eventOrigin = event->annotation().contract;
solAssert(eventOrigin);
solAssert(
*eventOrigin == _contractDef ||
(!eventOrigin->isLibrary() && _contractDef.derivesFrom(*eventOrigin)) ||
(eventOrigin->isLibrary() && !_contractDef.derivesFrom(*eventOrigin))
);
doc["events"][event->functionType(true)->externalSignature()] = devDoc;

}
for (auto const& error: _contractDef.interfaceErrors())
if (auto devDoc = devDocumentation(error->annotation().docTags); !devDoc.empty())
doc["errors"][error->functionType(true)->externalSignature()].append(devDoc);
Expand Down Expand Up @@ -255,3 +271,34 @@ Json::Value Natspec::devDocumentation(std::multimap<std::string, DocTag> const&

return json;
}

vector<EventDefinition const*> Natspec::uniqueInterfaceEvents(ContractDefinition const& _contract)
{
auto eventSignature = [](EventDefinition const* _event) -> string {
FunctionType const* functionType = _event->functionType(true);
solAssert(functionType, "");
return functionType->externalSignature();
};
auto compareBySignature =
[&](EventDefinition const* _lhs, EventDefinition const* _rhs) -> bool {
return eventSignature(_lhs) < eventSignature(_rhs);
};

set<EventDefinition const*, decltype(compareBySignature)> uniqueEvents{compareBySignature};
// Insert events defined in the contract first so that in case of a conflict
// they're the ones that get selected.
uniqueEvents += _contract.definedInterfaceEvents();

set<EventDefinition const*, decltype(compareBySignature)> filteredUsedEvents{compareBySignature};
set<string> usedSignatures;
for (EventDefinition const* event: _contract.usedInterfaceEvents())
{
auto&& [eventIt, eventInserted] = filteredUsedEvents.insert(event);
auto&& [signatureIt, signatureInserted] = usedSignatures.insert(eventSignature(event));
if (!signatureInserted)
filteredUsedEvents.erase(eventIt);
}

uniqueEvents += filteredUsedEvents;
return util::convertContainer<vector<EventDefinition const*>>(std::move(uniqueEvents));
}
7 changes: 7 additions & 0 deletions libsolidity/interface/Natspec.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ class Natspec
/// @return A JSON representation
/// of a method's return notice documentation
static Json::Value extractReturnParameterDocs(std::multimap<std::string, DocTag> const& _tags, std::vector<std::string> const& _returnParameterNames);

/// Temporary function until https://github.com/ethereum/solidity/issues/11114 is implemented.
/// @return all events defined in the contract and its base contracts and all events
/// that are emitted during the execution of the contract, but allowing only unique signatures.
/// In case of conflict between a library event and a contract one, selects the latter
/// In case of conflict between two library events, none is selected
static std::vector<EventDefinition const*> uniqueInterfaceEvents(ContractDefinition const& _contract);
};

}
2 changes: 1 addition & 1 deletion test/cmdlineTests/ast_compact_json_no_pretty_json/output
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ JSON AST (compact format):


======= ast_compact_json_no_pretty_json/input.sol =======
{"absolutePath":"ast_compact_json_no_pretty_json/input.sol","exportedSymbols":{"C":[2]},"id":3,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":2,"linearizedBaseContracts":[2],"name":"C","nameLocation":"69:1:0","nodeType":"ContractDefinition","nodes":[],"scope":3,"src":"60:13:0","usedErrors":[]}],"src":"36:38:0"}
{"absolutePath":"ast_compact_json_no_pretty_json/input.sol","exportedSymbols":{"C":[2]},"id":3,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":2,"linearizedBaseContracts":[2],"name":"C","nameLocation":"69:1:0","nodeType":"ContractDefinition","nodes":[],"scope":3,"src":"60:13:0","usedErrors":[],"usedEvents":[]}],"src":"36:38:0"}
3 changes: 2 additions & 1 deletion test/cmdlineTests/ast_compact_json_with_base_path/output
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ JSON AST (compact format):
"nodes": [],
"scope": 6,
"src": "60:13:0",
"usedErrors": []
"usedErrors": [],
"usedEvents": []
matheusaaguiar marked this conversation as resolved.
Show resolved Hide resolved
}
],
"src": "36:38:0"
Expand Down
3 changes: 2 additions & 1 deletion test/cmdlineTests/combined_json_with_base_path/output
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
"nodes": [],
"scope": 6,
"src": "60:13:0",
"usedErrors": []
"usedErrors": [],
"usedEvents": []
}
],
"src": "36:38:0"
Expand Down
1 change: 1 addition & 0 deletions test/cmdlineTests/events_in_abi/args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--abi --pretty-json --json-indent 4
16 changes: 16 additions & 0 deletions test/cmdlineTests/events_in_abi/input.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;
library L {
event e1(uint b);
}

function f() {
emit L.e1(5);
}

contract C {
event e1(uint indexed a);
function g() public {
f();
}
}
59 changes: 59 additions & 0 deletions test/cmdlineTests/events_in_abi/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

======= events_in_abi/input.sol:C =======
Contract JSON ABI
[
{
"anonymous": false,
"inputs":
[
{
"indexed": false,
"internalType": "uint256",
"name": "b",
"type": "uint256"
}
],
"name": "e1",
"type": "event"
},
{
"anonymous": false,
"inputs":
[
{
"indexed": true,
"internalType": "uint256",
"name": "a",
"type": "uint256"
}
],
"name": "e1",
"type": "event"
},
{
"inputs": [],
"name": "g",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

======= events_in_abi/input.sol:L =======
Contract JSON ABI
[
{
"anonymous": false,
"inputs":
[
{
"indexed": false,
"internalType": "uint256",
"name": "b",
"type": "uint256"
}
],
"name": "e1",
"type": "event"
}
]
3 changes: 2 additions & 1 deletion test/cmdlineTests/recovery_ast_constructor/output
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ JSON AST (compact format):
],
"scope": 19,
"src": "62:399:0",
"usedErrors": []
"usedErrors": [],
"usedEvents": []
}
],
"src": "36:426:0"
Expand Down
3 changes: 2 additions & 1 deletion test/cmdlineTests/recovery_standard_json/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
"nodes": [],
"scope": 4,
"src": "59:35:0",
"usedErrors": []
"usedErrors": [],
"usedEvents": []
}
],
"src": "36:84:0"
Expand Down
3 changes: 2 additions & 1 deletion test/cmdlineTests/standard_only_ast_requested/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@
],
"scope": 7,
"src": "59:42:0",
"usedErrors": []
"usedErrors": [],
"usedEvents": []
}
],
"src": "36:65:0"
Expand Down
71 changes: 71 additions & 0 deletions test/libsolidity/ABIJson/event_emited_in_base_contract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
library L { event E(uint8); }

contract B {
constructor() {
emit L.E(0);
}
}

contract C is B {}

// ----
// :B
// [
// {
// "inputs": [],
// "stateMutability": "nonpayable",
// "type": "constructor"
// },
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint8",
// "name": "",
// "type": "uint8"
// }
// ],
// "name": "E",
// "type": "event"
// }
// ]
//
//
// :C
// [
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint8",
// "name": "",
// "type": "uint8"
// }
// ],
// "name": "E",
// "type": "event"
// }
// ]
//
//
// :L
// [
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint8",
// "name": "",
// "type": "uint8"
// }
// ],
// "name": "E",
// "type": "event"
// }
// ]
Loading