Solidity 0.4.16 adds two new specifiers on contract functions: pure
and view
. Solidity 0.4.17 now enforces those specifiers—if you attempt to read or write to storage in the body of a function that claims not to do so, your contract will not compile.
- Pure has been introduced to specify functions that do not read or modify the storage of any contract, like math functions.
- View has been introduced to indicate functions that can never change the storage of any contract. View is an alias for constant, an existing specifier that was also not enforced by the compiler.
Use these specifiers to clarify the intended behavior of your functions. As you write your contracts, Solidity will suggest one of these state mutability specifiers when it detects functions that don't read and/or write to the contract's storage.
Today, pure and view only affect the JSON ABI that the compiler produces. The stateMutability
field for a function indicates whether the function is pure, view, nonpayable, or payable. Tools can access this data without parsing the contracts themselves to aid in generating reports or visualizations that make it easier to understand contracts.
The Byzantium network upgrade scheduled for October 9 will add a STATICCALL opcode that enforces read-only calls at runtime. Calls to and within pure or view functions can be compiled as STATICCALL, ensuring that the developer's expectations of immutability are never violated.
STATICCALL allows a subset of reentrancy vulnerabilities to be avoided: if a contract's state change depends on reading data from another contract, it can safely retrieve it without ever triggering a conflicting state change. However, if your contract's state change requires a successful state change in another contract, STATICCALL cannot be used, so you still need to take precautions against reentrancy.
The Disbursement contract in simple-token-sale allows tokens to vest gradually during a specified disbursement period. Disbursement.calcMaxWithdraw()
calculates the number of tokens that can currently be withdrawn. In the current codebase the function is specified as constant. In terms of the new specifiers, it is a view function---it reads from a contract's state but it doesn't modify it.
If we remove the existing constant
modifier in the codebase, Solidity will detect that the function is read-only:
Disbursement.sol:95:5: Warning: Function state mutability can be restricted to view
function calcMaxWithdraw()
^
Adding the view
modifier as shown below makes it clear that the function only reads from the state, and allows the compiler to help us maintain that behavior through the lifetime of the codebase.
/// @dev Calculates the maximum amount of vested tokens
/// @return Number of vested tokens to withdraw
function calcMaxWithdraw()
public
view
returns (uint)
{
uint maxTokens = (token.balanceOf(this) + withdrawnTokens) * (now - startDate) / disbursementPeriod;
if (withdrawnTokens >= maxTokens || startDate > now)
return 0;
return maxTokens - withdrawnTokens;
}
If we later modify the function and violate that specifier (intentionally or not), Solidity will warn us:
Disbursement.sol:102:9: Warning: Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
withdrawnTokens = 0;
^-------------^
To avoid overlooking this kind of behavior change, we can add pragma experimental "v0.5.0"
to the file to make the compilation fail with an error instead of just logging a warning.
The SafeMath contract
in zeppelin-solidity provides math functions that throw exceptions to prevent integer overflows. It's a library contract without its own state. In the current codebase, these functions are specified as constant, which indicates that the function doesn't write to the state, but doesn't let you know if it reads from the state. In terms of the new specifiers, these are pure functions---they don't read or write any state.
Compiling SafeMath
with the latest Solidity will throw several warnings like this one to let us know that the functions aren't just constant
or view
, they're pure
:
SafeMath.sol:27:3: Warning: Function state mutability can be restricted to pure
function add(uint256 a, uint256 b) internal constant returns (uint256) {
^
Updating these modifiers to pure
communicates the behavior more precisely:
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}