Skip to content

Commit

Permalink
Export all events.
Browse files Browse the repository at this point in the history
Update tests.

Additional tests

Revert changes to the Natspec
  • Loading branch information
chriseth authored and matheusaaguiar committed May 3, 2023
1 parent 1af6ca7 commit 1e63615
Show file tree
Hide file tree
Showing 139 changed files with 2,697 additions and 152 deletions.
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.
* 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.
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": []
}
],
"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

0 comments on commit 1e63615

Please sign in to comment.