Solidity tutorial 7 "Fallback Functions"

Fallback Functions

A contract can have exactly one unnamed function.
This function cannot have arguments and is executed on a call to the contract if none of the other functions matches the given function identifier (or if no data was supplied at all).

contract Test {
  function() { x = 1; }
  uint x;

contract Caller {
  function callTest(address testAddress) {
       results in Test(testAddress).x 
       becoming == 1.  

Function Modifiers

Modifiers can be used to easily change the behaviour of functions, for example to automatically check a condition prior to executing the function.
They are inheritable properties of contracts and may be overridden by derived contracts.

contract owned {
  function owned() { 
      owner = msg.sender; 
  address owner;}

This contract only defines a modifier but does not use it - it willbe used in derived contracts.
The function body is inserted where the special symbol "_" in the definition of a modifier appears.

modifier onlyowner { 
    if (msg.sender == owner)

contract mortal is owned
This contract inherits the onlyowner-modifier from owned and applies it to the kill-function, which causes that calls to kill only have an effect if they are made by the stored owner.

function kill() onlyowner {

contract priced
Modifiers can receive arguments:

  modifier costs(uint price) { 
      if (msg.value >= price)

contract Register is priced, owned

    mapping (address => bool) registeredAddresses;
     uint price;  
     function Register(uint initialPrice) { 
         price =initialPrice; 
         function register() costs(price) {
             registered Addresses[msg.sender] = true;  
               function changePrice(uint _price) onlyowner {
                   price = _price  

Multiple modifiers can be applied to a function by specifying them in a whitespace-separated list and will be evaluated in order.

Explicit returns from a modifier or function body immediately leave the whole function, while control flow reaching the end of a function or modifier body continues after the "_" in the preceding modifier.

Arbitrary expressions are allowed for modifier arguments and in this context, all symbols visible from the function are visible in the modifier.
Symbols introduced in the modifier are not visible in the function (as they might change by overriding).


Events allow the convenient usage of the EVM logging facilities.
Events are inheritable members of contracts.

When they are called, they cause the arguments to be stored in the transaction's log. Up to three parameters can receive the attribute indexed which will cause the respective arguments to be treated as log topics instead of data.

The hash of the signature of the event is one of the topics except you declared the event with anonymous specifier.
All non-indexed arguments will be stored in the data part of the log.


contract ClientReceipt {
    event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
  function deposit(bytes32 _id) {
    Deposit(msg.sender, _id, msg.value)  

Here, the call to Deposit will behave identical to log3.

// log3
msg.value, 0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20, sha3(msg.sender), _id

Note that the large hex number is equal to the sha3-hash of Deposit(address,bytes32,uint256), the event's signature.

Layout of Storage

Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position 0.

Multiple items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules:

  • The first item in a storage slot is stored lower-order aligned.
  • Elementary types use only that many bytes that are necessary to store them.
  • If an elementary type does not fit the remaining part of a storage slot, it is moved to the next storage slot.
  • Structs and array data always start a new slot and occupy whole slots (but items inside a struct or array are packed tightly according to these rules).
  • The elements of structs and arrays are stored after each other, just as if they were given explicitly.
  • Due to their unpredictable size, mapping and dynamically-sized array types use a sha3 computation to find the starting position of the value or the array data. These starting positions are always full stack slots.
  • The mapping or the dynamic array itself occupies an (unfilled) slot in storage at some position p according to the above rule (or by recursively applying this rule for mappings to mappings or arrays of arrays).

For a dynamic array, this slot stores the number of elements in the array.
For a mapping, the slot is unused (but it is needed so that two equal mappings after each other will use a different hash distribution).

Array data is located at sha3(p) and the value corresponding to a mapping key k is located at sha3(k . p) where. is concatenation.

If the value is again a non-elementary type, the positions are found by adding an offset of sha3(k . p).

So for the following contract snippet:

contract c {
      struct S {
           uint a; 
           uint b; 

        uint x;
        mapping(uint => mapping(uint => S)) data;

The position

data[4][9].b is at sha3(uint256(9) . sha3(uint256(4) . uint(256(1))) + 1

Esoteric Features

There are some types in Solidity's type system that have no counterpart in the syntax.
One of these types are the types of functions.
But still, using var it is possible to have local variables of these types:

contract FunctionSelector {
  function select(bool useB, uint x) returns (uint z) { 
      var f = a; if (useB) f = b; return f(x); 
  function a(uint x) returns (uint z) {
       return x * x; 
  function b(uint x) returns (uint z) { 
       return 2 * x;  

Calling select(false, x) will compute x x and select(true, x) will compute 2 x.

Next Lesson

Summary of Lessons



Boostlog is an online community for developers
who want to share ideas and grow each other.

Delete an article

Deleted articles are gone forever. Are you sure?