Refactor state as tuple

This commit is contained in:
Leonardo Alt 2020-09-07 16:45:14 +02:00
parent b0acf5dc86
commit a86f656704
2 changed files with 91 additions and 31 deletions

View File

@ -16,24 +16,42 @@
*/ */
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
#include "libsmtutil/SolverInterface.h"
#include <libsolidity/formal/SymbolicState.h> #include <libsolidity/formal/SymbolicState.h>
#include <libsolidity/formal/SymbolicTypes.h>
#include <libsolidity/formal/EncodingContext.h> #include <libsolidity/formal/EncodingContext.h>
using namespace std; using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::smtutil;
using namespace solidity::frontend::smt; using namespace solidity::frontend::smt;
SymbolicState::SymbolicState(EncodingContext& _context): SymbolicState::SymbolicState(EncodingContext& _context):
m_context(_context) m_context(_context)
{ {
m_stateMembers.emplace("balances", make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort));
vector<string> members;
vector<SortPointer> sorts;
for (auto const& [component, sort]: m_stateMembers)
{
members.emplace_back(component);
sorts.emplace_back(sort);
m_componentIndices[component] = members.size() - 1;
}
m_stateTuple = make_unique<SymbolicTupleVariable>(
make_shared<smtutil::TupleSort>("state_type", members, sorts),
"state",
m_context
);
} }
void SymbolicState::reset() void SymbolicState::reset()
{ {
m_thisAddress.resetIndex();
m_balances.resetIndex();
m_error.resetIndex(); m_error.resetIndex();
m_thisAddress.resetIndex();
m_stateTuple->resetIndex();
} }
// Blockchain // Blockchain
@ -43,14 +61,19 @@ smtutil::Expression SymbolicState::thisAddress()
return m_thisAddress.currentValue(); return m_thisAddress.currentValue();
} }
smtutil::Expression SymbolicState::balances()
{
return m_stateTuple->component(m_componentIndices.at("balances"));
}
smtutil::Expression SymbolicState::balance() smtutil::Expression SymbolicState::balance()
{ {
return balance(m_thisAddress.currentValue()); return balance(thisAddress());
} }
smtutil::Expression SymbolicState::balance(smtutil::Expression _address) smtutil::Expression SymbolicState::balance(smtutil::Expression _address)
{ {
return smtutil::Expression::select(m_balances.elements(), move(_address)); return smtutil::Expression::select(balances(), move(_address));
} }
SymbolicIntVariable& SymbolicState::errorFlag() SymbolicIntVariable& SymbolicState::errorFlag()
@ -58,21 +81,31 @@ SymbolicIntVariable& SymbolicState::errorFlag()
return m_error; return m_error;
} }
smtutil::Expression SymbolicState::state()
{
return m_stateTuple->currentValue();
}
SortPointer SymbolicState::stateSort()
{
return m_stateTuple->sort();
}
void SymbolicState::transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value) void SymbolicState::transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value)
{ {
unsigned indexBefore = m_balances.index(); unsigned indexBefore = m_stateTuple->index();
addBalance(_from, 0 - _value); addBalance(_from, 0 - _value);
addBalance(_to, move(_value)); addBalance(_to, move(_value));
unsigned indexAfter = m_balances.index(); unsigned indexAfter = m_stateTuple->index();
solAssert(indexAfter > indexBefore, ""); solAssert(indexAfter > indexBefore, "");
m_balances.increaseIndex(); m_stateTuple->increaseIndex();
/// Do not apply the transfer operation if _from == _to. /// Do not apply the transfer operation if _from == _to.
auto newBalances = smtutil::Expression::ite( auto newState = smtutil::Expression::ite(
move(_from) == move(_to), move(_from) == move(_to),
m_balances.valueAtIndex(indexBefore), m_stateTuple->valueAtIndex(indexBefore),
m_balances.valueAtIndex(indexAfter) m_stateTuple->valueAtIndex(indexAfter)
); );
m_context.addAssertion(m_balances.currentValue() == newBalances); m_context.addAssertion(m_stateTuple->currentValue() == newState);
} }
/// Private helpers. /// Private helpers.
@ -80,13 +113,24 @@ void SymbolicState::transfer(smtutil::Expression _from, smtutil::Expression _to,
void SymbolicState::addBalance(smtutil::Expression _address, smtutil::Expression _value) void SymbolicState::addBalance(smtutil::Expression _address, smtutil::Expression _value)
{ {
auto newBalances = smtutil::Expression::store( auto newBalances = smtutil::Expression::store(
m_balances.elements(), balances(),
_address, _address,
balance(_address) + move(_value) balance(_address) + move(_value)
); );
auto oldLength = m_balances.length(); assignStateMember("balances", newBalances);
m_balances.increaseIndex();
m_context.addAssertion(m_balances.elements() == newBalances);
m_context.addAssertion(m_balances.length() == oldLength);
} }
smtutil::Expression SymbolicState::assignStateMember(string const& _member, smtutil::Expression const& _value)
{
vector<smtutil::Expression> args;
for (auto const& member: m_stateMembers)
if (member.first == _member)
args.emplace_back(_value);
else
args.emplace_back(m_stateTuple->component(m_componentIndices.at(member.first)));
m_stateTuple->increaseIndex();
auto tuple = m_stateTuple->currentValue();
auto sortExpr = smtutil::Expression(make_shared<smtutil::SortSort>(tuple.sort), tuple.name);
m_context.addAssertion(tuple == smtutil::Expression::tuple_constructor(sortExpr, args));
return m_stateTuple->currentValue();
}

View File

@ -27,9 +27,17 @@ namespace solidity::frontend::smt
{ {
class EncodingContext; class EncodingContext;
class SymbolicAddressVariable;
class SymbolicArrayVariable;
/** /**
* Symbolic representation of the blockchain state. * Symbolic representation of the blockchain context:
* - error flag
* - this (the address of the currently executing contract)
* - state, represented as a tuple of:
* - balances
* - TODO: potentially storage of contracts
* - TODO transaction variables
*/ */
class SymbolicState class SymbolicState
{ {
@ -42,6 +50,8 @@ public:
//@{ //@{
/// Value of `this` address. /// Value of `this` address.
smtutil::Expression thisAddress(); smtutil::Expression thisAddress();
/// @returns the symbolic balances.
smtutil::Expression balances();
/// @returns the symbolic balance of address `this`. /// @returns the symbolic balance of address `this`.
smtutil::Expression balance(); smtutil::Expression balance();
/// @returns the symbolic balance of an address. /// @returns the symbolic balance of an address.
@ -49,6 +59,12 @@ public:
SymbolicIntVariable& errorFlag(); SymbolicIntVariable& errorFlag();
/// @returns the state as a tuple.
smtutil::Expression state();
/// @returns the state sort.
smtutil::SortPointer stateSort();
/// Transfer _value from _from to _to. /// Transfer _value from _from to _to.
void transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value); void transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value);
//@} //@}
@ -57,27 +73,27 @@ private:
/// Adds _value to _account's balance. /// Adds _value to _account's balance.
void addBalance(smtutil::Expression _account, smtutil::Expression _value); void addBalance(smtutil::Expression _account, smtutil::Expression _value);
/// Generates a new tuple where _member is assigned _value.
smtutil::Expression assignStateMember(std::string const& _member, smtutil::Expression const& _value);
EncodingContext& m_context; EncodingContext& m_context;
/// Symbolic `this` address. SymbolicIntVariable m_error{
SymbolicAddressVariable m_thisAddress{
"this",
m_context
};
/// Symbolic balances.
SymbolicArrayVariable m_balances{
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort),
"balances",
m_context
};
smt::SymbolicIntVariable m_error{
TypeProvider::uint256(), TypeProvider::uint256(),
TypeProvider::uint256(), TypeProvider::uint256(),
"error", "error",
m_context m_context
}; };
SymbolicAddressVariable m_thisAddress{
"this",
m_context
};
std::map<std::string, unsigned> m_componentIndices;
/// balances, TODO storage of other contracts
std::map<std::string, smtutil::SortPointer> m_stateMembers;
std::unique_ptr<SymbolicTupleVariable> m_stateTuple;
}; };
} }