Skip to content

Commit cbac3a4

Browse files
author
Leonardo
authored
Merge pull request ethereum#7107 from ethereum/smt_chc_constructor_interface
[SMTChecker] Add CHC constructor/interface/error blocks
2 parents dcf2e49 + bef6228 commit cbac3a4

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

libsolidity/formal/CHC.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,52 @@ bool CHC::visit(ContractDefinition const& _contract)
6565
if (!SMTEncoder::visit(_contract))
6666
return false;
6767

68+
m_stateVariables = _contract.stateVariablesIncludingInherited();
69+
70+
for (auto const& var: m_stateVariables)
71+
// SMT solvers do not support function types as arguments.
72+
if (var->type()->category() == Type::Category::Function)
73+
m_stateSorts.push_back(make_shared<smt::Sort>(smt::Kind::Int));
74+
else
75+
m_stateSorts.push_back(smt::smtSort(*var->type()));
76+
77+
string interfaceName = "interface_" + _contract.name() + "_" + to_string(_contract.id());
78+
m_interfacePredicate = createBlock(interfaceSort(), interfaceName);
79+
80+
// TODO create static instances for Bool/Int sorts in SolverInterface.
81+
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
82+
auto errorFunctionSort = make_shared<smt::FunctionSort>(
83+
vector<smt::SortPointer>(),
84+
boolSort
85+
);
86+
m_errorPredicate = createBlock(errorFunctionSort, "error");
87+
88+
// If the contract has a constructor it is handled as a function.
89+
// Otherwise we zero-initialize all state vars.
90+
// TODO take into account state vars init values.
91+
if (!_contract.constructor())
92+
{
93+
string constructorName = "constructor_" + _contract.name() + "_" + to_string(_contract.id());
94+
m_constructorPredicate = createBlock(constructorSort(), constructorName);
95+
96+
for (auto const& var: m_stateVariables)
97+
{
98+
auto const& symbVar = m_context.variable(*var);
99+
symbVar->increaseIndex();
100+
m_interface->declareVariable(symbVar->currentName(), *symbVar->sort());
101+
m_context.setZeroValue(*symbVar);
102+
}
103+
104+
smt::Expression constructorAppl = (*m_constructorPredicate)({});
105+
m_interface->addRule(constructorAppl, constructorName);
106+
107+
smt::Expression constructorInterface = smt::Expression::implies(
108+
constructorAppl && m_context.assertions(),
109+
interface()
110+
);
111+
m_interface->addRule(constructorInterface, constructorName + "_to_" + interfaceName);
112+
}
113+
68114
return true;
69115
}
70116

@@ -73,6 +119,11 @@ void CHC::endVisit(ContractDefinition const& _contract)
73119
if (!shouldVisit(_contract))
74120
return;
75121

122+
auto errorAppl = (*m_errorPredicate)({});
123+
for (auto const& target: m_verificationTargets)
124+
if (query(errorAppl, target->location()))
125+
m_safeAssertions.insert(target);
126+
76127
SMTEncoder::endVisit(_contract);
77128
}
78129

@@ -131,6 +182,8 @@ void CHC::visitAssert(FunctionCall const&)
131182

132183
void CHC::reset()
133184
{
185+
m_stateSorts.clear();
186+
m_stateVariables.clear();
134187
m_verificationTargets.clear();
135188
m_safeAssertions.clear();
136189
}
@@ -155,6 +208,71 @@ bool CHC::shouldVisit(FunctionDefinition const& _function) const
155208
return false;
156209
}
157210

211+
smt::SortPointer CHC::constructorSort()
212+
{
213+
solAssert(m_currentContract, "");
214+
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
215+
if (!m_currentContract->constructor())
216+
return make_shared<smt::FunctionSort>(vector<smt::SortPointer>{}, boolSort);
217+
return functionSort(*m_currentContract->constructor());
218+
}
219+
220+
smt::SortPointer CHC::interfaceSort()
221+
{
222+
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
223+
return make_shared<smt::FunctionSort>(
224+
m_stateSorts,
225+
boolSort
226+
);
227+
}
228+
229+
smt::SortPointer CHC::functionSort(FunctionDefinition const& _function)
230+
{
231+
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
232+
auto const& funType = dynamic_cast<FunctionType const&>(*_function.type());
233+
return make_shared<smt::FunctionSort>(
234+
smt::smtSort(funType.parameterTypes()),
235+
boolSort
236+
);
237+
}
238+
239+
unique_ptr<smt::SymbolicFunctionVariable> CHC::createBlock(smt::SortPointer _sort, string const& _name)
240+
{
241+
auto block = make_unique<smt::SymbolicFunctionVariable>(
242+
_sort,
243+
_name,
244+
m_context
245+
);
246+
m_interface->registerRelation(block->currentValue());
247+
return block;
248+
}
249+
250+
smt::Expression CHC::constructor()
251+
{
252+
solAssert(m_currentContract, "");
253+
254+
if (!m_currentContract->constructor())
255+
return (*m_constructorPredicate)({});
256+
257+
vector<smt::Expression> paramExprs;
258+
for (auto const& var: m_currentContract->constructor()->parameters())
259+
paramExprs.push_back(m_context.variable(*var)->currentValue());
260+
return (*m_constructorPredicate)(paramExprs);
261+
}
262+
263+
smt::Expression CHC::interface()
264+
{
265+
vector<smt::Expression> paramExprs;
266+
for (auto const& var: m_stateVariables)
267+
paramExprs.push_back(m_context.variable(*var)->currentValue());
268+
return (*m_interfacePredicate)(paramExprs);
269+
}
270+
271+
smt::Expression CHC::error()
272+
{
273+
return (*m_errorPredicate)({});
274+
}
275+
158276
bool CHC::query(smt::Expression const& _query, langutil::SourceLocation const& _location)
159277
{
160278
smt::CheckResult result;

libsolidity/formal/CHC.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,57 @@ class CHC: public SMTEncoder
7070
bool shouldVisit(FunctionDefinition const& _function) const;
7171
//@}
7272

73+
/// Sort helpers.
74+
//@{
75+
smt::SortPointer constructorSort();
76+
smt::SortPointer interfaceSort();
77+
smt::SortPointer functionSort(FunctionDefinition const& _function);
78+
//@}
79+
80+
/// Predicate helpers.
81+
//@{
82+
/// @returns a new block of given _sort and _name.
83+
std::unique_ptr<smt::SymbolicFunctionVariable> createBlock(smt::SortPointer _sort, std::string const& _name);
84+
85+
/// Constructor predicate over current variables.
86+
smt::Expression constructor();
87+
/// Interface predicate over current variables.
88+
smt::Expression interface();
89+
/// Error predicate over current variables.
90+
smt::Expression error();
91+
//@}
92+
7393
/// Solver related.
7494
//@{
7595
/// @returns true if query is unsatisfiable (safe).
7696
bool query(smt::Expression const& _query, langutil::SourceLocation const& _location);
7797
//@}
7898

99+
/// Predicates.
100+
//@{
101+
/// Constructor predicate.
102+
/// Default constructor sets state vars to 0.
103+
std::unique_ptr<smt::SymbolicVariable> m_constructorPredicate;
104+
105+
/// Artificial Interface predicate.
106+
/// Single entry block for all functions.
107+
std::unique_ptr<smt::SymbolicVariable> m_interfacePredicate;
108+
109+
/// Artificial Error predicate.
110+
/// Single error block for all assertions.
111+
std::unique_ptr<smt::SymbolicVariable> m_errorPredicate;
112+
//@}
113+
114+
/// Variables.
115+
//@{
116+
/// State variables sorts.
117+
/// Used by all predicates.
118+
std::vector<smt::SortPointer> m_stateSorts;
119+
/// State variables.
120+
/// Used to create all predicates.
121+
std::vector<VariableDeclaration const*> m_stateVariables;
122+
//@}
123+
79124
/// Verification targets.
80125
//@{
81126
std::vector<Expression const*> m_verificationTargets;

libsolidity/formal/SMTEncoder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
4040
m_currentContract = &_contract;
4141

4242
initializeStateVariables(_contract);
43+
4344
return true;
4445
}
4546

0 commit comments

Comments
 (0)