Export all events.

This commit is contained in:
chriseth 2021-02-23 14:13:52 +01:00 committed by wechman
parent 548a4b4ac6
commit 049ef229c8
15 changed files with 797 additions and 5 deletions

View File

@ -1,7 +1,10 @@
### 0.8.17 (unreleased) ### 0.8.17 (unreleased)
Important Bugfixes: Important Bugfixes:
* ABI: Include events in the ABI that are emitted by a contract but defined outside of it.
AST Changes:
* Add field ``emittedEvents`` to ``ContractDefinition`` which contains the AST IDs of all inherited and emitted events.
Language Features: Language Features:

View File

@ -232,7 +232,7 @@ vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents
vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const
{ {
solAssert(annotation().creationCallGraph.set(), ""); solAssert(annotation().creationCallGraph.set());
return util::convertContainer<std::vector<EventDefinition const*>>( return util::convertContainer<std::vector<EventDefinition const*>>(
(*annotation().creationCallGraph)->emittedEvents + (*annotation().creationCallGraph)->emittedEvents +
@ -240,14 +240,29 @@ 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 vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
{ {
set<ErrorDefinition const*, CompareByID> result; set<ErrorDefinition const*, CompareByID> result;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts) for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
result += filteredNodes<ErrorDefinition>(contract->m_subNodes); result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set(), ""); solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set());
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 +

View File

@ -522,6 +522,10 @@ public:
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& definedInterfaceEvents() const; std::vector<EventDefinition const*> const& definedInterfaceEvents() const;
std::vector<EventDefinition const*> const usedInterfaceEvents() 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 /// @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.

View File

@ -285,6 +285,8 @@ bool ASTJsonExporter::visit(ContractDefinition const& _node)
make_pair("abstract", _node.abstract()), make_pair("abstract", _node.abstract()),
make_pair("baseContracts", toJson(_node.baseContracts())), make_pair("baseContracts", toJson(_node.baseContracts())),
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)), 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("emittedEvents", getContainerIds(_node.interfaceEvents(false))),
make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))), make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))),
make_pair("nodes", toJson(_node.subNodes())), make_pair("nodes", toJson(_node.subNodes())),
make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))

View File

@ -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.definedInterfaceEvents()) for (auto const& it: _contractDef.interfaceEvents())
{ {
Json::Value event{Json::objectValue}; Json::Value event{Json::objectValue};
event["type"] = "event"; event["type"] = "event";

View File

@ -0,0 +1 @@
--abi --pretty-json --json-indent 4

View File

@ -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();
}
}

View File

@ -0,0 +1,8 @@
======= 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"}]

View File

@ -0,0 +1,88 @@
library L {
event e1(uint b);
event e2();
event e2(uint a);
event e3() anonymous;
}
contract test {
function f() public {
emit L.e1(1);
emit L.e3();
}
}
// ----
// :L
// [
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint256",
// "name": "b",
// "type": "uint256"
// }
// ],
// "name": "e1",
// "type": "event"
// },
// {
// "anonymous": false,
// "inputs": [],
// "name": "e2",
// "type": "event"
// },
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint256",
// "name": "a",
// "type": "uint256"
// }
// ],
// "name": "e2",
// "type": "event"
// },
// {
// "anonymous": true,
// "inputs": [],
// "name": "e3",
// "type": "event"
// }
// ]
//
//
// :test
// [
// {
// "anonymous": false,
// "inputs":
// [
// {
// "indexed": false,
// "internalType": "uint256",
// "name": "b",
// "type": "uint256"
// }
// ],
// "name": "e1",
// "type": "event"
// },
// {
// "anonymous": true,
// "inputs": [],
// "name": "e3",
// "type": "event"
// },
// {
// "inputs": [],
// "name": "f",
// "outputs": [],
// "stateMutability": "nonpayable",
// "type": "function"
// }
// ]

View File

@ -0,0 +1,45 @@
library L {
event e();
}
contract C {
constructor() {
emit L.e();
}
function f() public {
emit L.e();
}
}
// ----
// :C
// [
// {
// "inputs": [],
// "stateMutability": "nonpayable",
// "type": "constructor"
// },
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// },
// {
// "inputs": [],
// "name": "f",
// "outputs": [],
// "stateMutability": "nonpayable",
// "type": "function"
// }
// ]
//
//
// :L
// [
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// }
// ]

View File

@ -0,0 +1,61 @@
library L1 { event e(); }
library L2 { event e(); }
contract C {
constructor() {
emit L1.e();
}
function f() public {
emit L2.e();
}
}
// ----
// :C
// [
// {
// "inputs": [],
// "stateMutability": "nonpayable",
// "type": "constructor"
// },
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// },
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// },
// {
// "inputs": [],
// "name": "f",
// "outputs": [],
// "stateMutability": "nonpayable",
// "type": "function"
// }
// ]
//
//
// :L1
// [
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// }
// ]
//
//
// :L2
// [
// {
// "anonymous": false,
// "inputs": [],
// "name": "e",
// "type": "event"
// }
// ]

View File

@ -0,0 +1,313 @@
{
"absolutePath": "a",
"exportedSymbols":
{
"C":
[
25
],
"L":
[
10
]
},
"id": 26,
"license": "GPL-3.0",
"nodeType": "SourceUnit",
"nodes":
[
{
"abstract": false,
"baseContracts": [],
"canonicalName": "L",
"contractDependencies": [],
"contractKind": "library",
"emittedEvents":
[
2
],
"fullyImplemented": true,
"id": 10,
"linearizedBaseContracts":
[
10
],
"name": "L",
"nameLocation": "44:1:1",
"nodeType": "ContractDefinition",
"nodes":
[
{
"anonymous": false,
"id": 2,
"name": "E",
"nameLocation": "58:1:1",
"nodeType": "EventDefinition",
"parameters":
{
"id": 1,
"nodeType": "ParameterList",
"parameters": [],
"src": "59:2:1"
},
"src": "52:10:1"
},
{
"body":
{
"id": 8,
"nodeType": "Block",
"src": "89:13:1",
"statements":
[
{
"eventCall":
{
"arguments": [],
"expression":
{
"argumentTypes": [],
"id": 5,
"name": "E",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 2,
"src": "96:1:1",
"typeDescriptions":
{
"typeIdentifier": "t_function_event_nonpayable$__$returns$__$",
"typeString": "function ()"
}
},
"id": 6,
"isConstant": false,
"isLValue": false,
"isPure": false,
"kind": "functionCall",
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "96:3:1",
"tryCall": false,
"typeDescriptions":
{
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 7,
"nodeType": "EmitStatement",
"src": "91:8:1"
}
]
},
"id": 9,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "f",
"nameLocation": "76:1:1",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 3,
"nodeType": "ParameterList",
"parameters": [],
"src": "77:2:1"
},
"returnParameters":
{
"id": 4,
"nodeType": "ParameterList",
"parameters": [],
"src": "89:0:1"
},
"scope": 10,
"src": "67:35:1",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "internal"
}
],
"scope": 26,
"src": "36:68:1",
"usedErrors": []
},
{
"abstract": false,
"baseContracts": [],
"canonicalName": "C",
"contractDependencies": [],
"contractKind": "contract",
"emittedEvents":
[
2,
12
],
"fullyImplemented": true,
"id": 25,
"linearizedBaseContracts":
[
25
],
"name": "C",
"nameLocation": "114:1:1",
"nodeType": "ContractDefinition",
"nodes":
[
{
"anonymous": false,
"id": 12,
"name": "H",
"nameLocation": "128:1:1",
"nodeType": "EventDefinition",
"parameters":
{
"id": 11,
"nodeType": "ParameterList",
"parameters": [],
"src": "129:2:1"
},
"src": "122:10:1"
},
{
"body":
{
"id": 23,
"nodeType": "Block",
"src": "157:20:1",
"statements":
[
{
"expression":
{
"arguments": [],
"expression":
{
"argumentTypes": [],
"expression":
{
"id": 15,
"name": "L",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 10,
"src": "159:1:1",
"typeDescriptions":
{
"typeIdentifier": "t_type$_t_contract$_L_$10_$",
"typeString": "type(library L)"
}
},
"id": 17,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"memberName": "f",
"nodeType": "MemberAccess",
"referencedDeclaration": 9,
"src": "159:3:1",
"typeDescriptions":
{
"typeIdentifier": "t_function_internal_nonpayable$__$returns$__$",
"typeString": "function ()"
}
},
"id": 18,
"isConstant": false,
"isLValue": false,
"isPure": false,
"kind": "functionCall",
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "159:5:1",
"tryCall": false,
"typeDescriptions":
{
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 19,
"nodeType": "ExpressionStatement",
"src": "159:5:1"
},
{
"eventCall":
{
"arguments": [],
"expression":
{
"argumentTypes": [],
"id": 20,
"name": "H",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 12,
"src": "171:1:1",
"typeDescriptions":
{
"typeIdentifier": "t_function_event_nonpayable$__$returns$__$",
"typeString": "function ()"
}
},
"id": 21,
"isConstant": false,
"isLValue": false,
"isPure": false,
"kind": "functionCall",
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "171:3:1",
"tryCall": false,
"typeDescriptions":
{
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 22,
"nodeType": "EmitStatement",
"src": "166:8:1"
}
]
},
"functionSelector": "e2179b8e",
"id": 24,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "g",
"nameLocation": "146:1:1",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 13,
"nodeType": "ParameterList",
"parameters": [],
"src": "147:2:1"
},
"returnParameters":
{
"id": 14,
"nodeType": "ParameterList",
"parameters": [],
"src": "157:0:1"
},
"scope": 25,
"src": "137:40:1",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "public"
}
],
"scope": 26,
"src": "105:74:1",
"usedErrors": []
}
],
"src": "36:144:1"
}

View File

@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-3.0
library L {
event E();
function f() internal { emit E(); }
}
contract C {
event H();
function g() public { L.f(); emit H(); }
}
// ----

View File

@ -0,0 +1,224 @@
{
"absolutePath": "a",
"id": 26,
"license": "GPL-3.0",
"nodeType": "SourceUnit",
"nodes":
[
{
"abstract": false,
"baseContracts": [],
"contractDependencies": [],
"contractKind": "library",
"emittedEvents": [],
"id": 10,
"name": "L",
"nameLocation": "44:1:1",
"nodeType": "ContractDefinition",
"nodes":
[
{
"anonymous": false,
"id": 2,
"name": "E",
"nameLocation": "58:1:1",
"nodeType": "EventDefinition",
"parameters":
{
"id": 1,
"nodeType": "ParameterList",
"parameters": [],
"src": "59:2:1"
},
"src": "52:10:1"
},
{
"body":
{
"id": 8,
"nodeType": "Block",
"src": "89:13:1",
"statements":
[
{
"eventCall":
{
"arguments": [],
"expression":
{
"id": 5,
"name": "E",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"src": "96:1:1",
"typeDescriptions": {}
},
"id": 6,
"names": [],
"nodeType": "FunctionCall",
"src": "96:3:1",
"tryCall": false,
"typeDescriptions": {}
},
"id": 7,
"nodeType": "EmitStatement",
"src": "91:8:1"
}
]
},
"id": 9,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "f",
"nameLocation": "76:1:1",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 3,
"nodeType": "ParameterList",
"parameters": [],
"src": "77:2:1"
},
"returnParameters":
{
"id": 4,
"nodeType": "ParameterList",
"parameters": [],
"src": "89:0:1"
},
"src": "67:35:1",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "internal"
}
],
"src": "36:68:1",
"usedErrors": []
},
{
"abstract": false,
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"emittedEvents": [],
"id": 25,
"name": "C",
"nameLocation": "114:1:1",
"nodeType": "ContractDefinition",
"nodes":
[
{
"anonymous": false,
"id": 12,
"name": "H",
"nameLocation": "128:1:1",
"nodeType": "EventDefinition",
"parameters":
{
"id": 11,
"nodeType": "ParameterList",
"parameters": [],
"src": "129:2:1"
},
"src": "122:10:1"
},
{
"body":
{
"id": 23,
"nodeType": "Block",
"src": "157:20:1",
"statements":
[
{
"expression":
{
"arguments": [],
"expression":
{
"expression":
{
"id": 15,
"name": "L",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"src": "159:1:1",
"typeDescriptions": {}
},
"id": 17,
"memberName": "f",
"nodeType": "MemberAccess",
"src": "159:3:1",
"typeDescriptions": {}
},
"id": 18,
"names": [],
"nodeType": "FunctionCall",
"src": "159:5:1",
"tryCall": false,
"typeDescriptions": {}
},
"id": 19,
"nodeType": "ExpressionStatement",
"src": "159:5:1"
},
{
"eventCall":
{
"arguments": [],
"expression":
{
"id": 20,
"name": "H",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"src": "171:1:1",
"typeDescriptions": {}
},
"id": 21,
"names": [],
"nodeType": "FunctionCall",
"src": "171:3:1",
"tryCall": false,
"typeDescriptions": {}
},
"id": 22,
"nodeType": "EmitStatement",
"src": "166:8:1"
}
]
},
"id": 24,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "g",
"nameLocation": "146:1:1",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 13,
"nodeType": "ParameterList",
"parameters": [],
"src": "147:2:1"
},
"returnParameters":
{
"id": 14,
"nodeType": "ParameterList",
"parameters": [],
"src": "157:0:1"
},
"src": "137:40:1",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "public"
}
],
"src": "105:74:1",
"usedErrors": []
}
],
"src": "36:144:1"
}

View File

@ -485,7 +485,8 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
util::jsonCompactPrint(result["sources"]["fileA"]["ast"]), util::jsonCompactPrint(result["sources"]["fileA"]["ast"]),
"{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]},\"id\":2,\"nodeType\":\"SourceUnit\",\"nodes\":[{\"abstract\":false," "{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]},\"id\":2,\"nodeType\":\"SourceUnit\",\"nodes\":[{\"abstract\":false,"
"\"baseContracts\":[],\"canonicalName\":\"A\",\"contractDependencies\":[],\"contractKind\":\"contract\",\"fullyImplemented\":true,\"id\":1," "\"baseContracts\":[],\"canonicalName\":\"A\",\"contractDependencies\":[],"
"\"contractKind\":\"contract\",\"emittedEvents\":[],\"fullyImplemented\":true,\"id\":1,"
"\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nameLocation\":\"9:1:0\",\"nodeType\":\"ContractDefinition\",\"nodes\":[],\"scope\":2," "\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nameLocation\":\"9:1:0\",\"nodeType\":\"ContractDefinition\",\"nodes\":[],\"scope\":2,"
"\"src\":\"0:14:0\",\"usedErrors\":[]}],\"src\":\"0:14:0\"}" "\"src\":\"0:14:0\",\"usedErrors\":[]}],\"src\":\"0:14:0\"}"
); );