Function Annotations
Function specifications are used to specify the behaviour of a single function.
Successful termination
Scribble currently has a single type of function specification, called if_succeeds
. Using if_succeeds, annotations you can assert properties that you expect to hold if (and only if) the annotated function successfully terminates.
These annotations have the following structure & are placed right above a function declaration:
The following is a simple example property, where we check that the function always returns 0.
Note that as of Scribble 0.4.0 you can also specify an if_succeeds
annotation at the contract level. See the section below.
Encoding Pre- and Post- Conditions
Pre- and postconditions are frequently used concepts in verification languages.
A precondition is what should be true before a function is executed.
A postcondition is what should be true after the function, if the precondition was true.
In it's simplest form if_succeeds
allows you to write postconditions (i.e. properties over the state after the function is done).
However, if_succeeds is quite versatile and you can use it to check preconditions as well. You'd do so by using the old() function.
We expect that a selfdestruct function only succeeds if the transaction sender is the owner of the contract.
Encoding conditional "behaviors"
Functions can have multiple behaviors depending on the inputs and contract state. Take the following example of a simple calculator function implementing multiplication and addition.
In this case, there are two distinct behaviors: multiplication and addition. Writing two separate post-conditions wouldn't work, since scribble
checks the conjunction of all function annotations.
Luckily, you can use the implication operator here to describe the conditions under which each behavior holds:
Contract-level if_succeeds annotations
As of Scribble 0.4.0 you can also specify an if_succeeds
annotation at the contract level. A contract-level if_succeeds
is automatically applied to all public and external functions in the annotated contract, and all inheriting contracts. For example, in the below sample the annotation x > 0
will be applied to the functions A.pubFun
, A.externFun
and B.pubFunB
. Note that pure
and view
functions are skipped. So in the below example A.pubViewFun
will not be annotated.
Note that since the same expression needs to hold for an unknown set of functions, when writing a contract-level if_succeeds
function you can only talk about the contract's state vars, and other global transaction state. You cannot refer to function arguments/returns (even if all functions in the contract have the same arguments or returns).
Last updated