aboutsummaryrefslogtreecommitdiffstats
path: root/docs/contracts/events.rst
blob: ecb0a87f8a118936aa68435cb70677292b915f8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
.. index:: ! event

.. _events:

******
Events
******

Solidity events give an abstraction on top of the EVM's logging functionality.
Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.

Events are inheritable members of contracts. When you call them, they cause the
arguments to be stored in the transaction's log - a special data structure
in the blockchain. These logs are associated with the address of the contract,
are incorporated into the blockchain, and stay there as long as a block is
accessible (forever as of the Frontier and Homestead releases, but this might
change with Serenity). The Log and its event data is not accessible from within
contracts (not even from the contract that created them).

It is possible to request a simple payment verification (SPV) for logs, so if
an external entity supplies a contract with such a verification, it can check
that the log actually exists inside the blockchain. You have to supply block headers
because the contract can only see the last 256 block hashes.

You can add the attribute ``indexed`` to up to three parameters which adds them
to a special data structure known as :ref:`"topics" <abi_events>` instead of
the data part of the log. If you use arrays (including ``string`` and ``bytes``)
as indexed arguments, its Keccak-256 hash is stored as a topic instead, this is
because a topic can only hold a single word (32 bytes).

All parameters without the ``indexed`` attribute are :ref:`ABI-encoded <ABI>`
into the data part of the log.

Topics allow you to search for events, for example when filtering a sequence of
blocks for certain events. You can also filter events by the address of the
contract that emitted the event.

For example, the code below uses the web3.js ``subscribe("logs")``
`method <https://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-logs>`_ to filter
logs that match a topic with a certain address value:

.. code-block:: javascript

    var options = {
        fromBlock: 0,
        address: web3.eth.defaultAccount,
        topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
    };
    web3.eth.subscribe('logs', options, function (error, result) {
        if (!error)
            console.log(result);
    })
        .on("data", function (log) {
            console.log(log);
        })
        .on("changed", function (log) {
    });


The hash of the signature of the event is one of the topics, except if you
declared the event with the ``anonymous`` specifier. This means that it is
not possible to filter for specific anonymous events by name.

::

    pragma solidity >=0.4.21 <0.6.0;

    contract ClientReceipt {
        event Deposit(
            address indexed _from,
            bytes32 indexed _id,
            uint _value
        );

        function deposit(bytes32 _id) public payable {
            // Events are emitted using `emit`, followed by
            // the name of the event and the arguments
            // (if any) in parentheses. Any such invocation
            // (even deeply nested) can be detected from
            // the JavaScript API by filtering for `Deposit`.
            emit Deposit(msg.sender, _id, msg.value);
        }
    }

The use in the JavaScript API is as follows:

::

    var abi = /* abi as generated by the compiler */;
    var ClientReceipt = web3.eth.contract(abi);
    var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);

    var event = clientReceipt.Deposit();

    // watch for changes
    event.watch(function(error, result){
        // result contains non-indexed arguments and topics
        // given to the `Deposit` call.
        if (!error)
            console.log(result);
    });


    // Or pass a callback to start watching immediately
    var event = clientReceipt.Deposit(function(error, result) {
        if (!error)
            console.log(result);
    });

The output of the above looks like the following (trimmed):

.. code-block:: json

  {
     "returnValues": {
         "_from": "0x1111…FFFFCCCC",
         "_id": "0x50…sd5adb20",
         "_value": "0x420042"
     },
     "raw": {
         "data": "0x7f91385",
         "topics": ["0xfd4…b4ead7", "0x7f1a91385"]
     }
  }

.. index:: ! log

Low-Level Interface to Logs
===========================

It is also possible to access the low-level interface to the logging
mechanism via the functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4``.
``logi`` takes ``i + 1`` parameter of type ``bytes32``, where the first
argument will be used for the data part of the log and the others
as topics. The event call above can be performed in the same way as

::

    pragma solidity >=0.4.10 <0.6.0;

    contract C {
        function f() public payable {
            uint256 _id = 0x420042;
            log3(
                bytes32(msg.value),
                bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20),
                bytes32(uint256(msg.sender)),
                bytes32(_id)
            );
        }
    }

where the long hexadecimal number is equal to
``keccak256("Deposit(address,bytes32,uint256)")``, the signature of the event.

Additional Resources for Understanding Events
==============================================

- `Javascript documentation <https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-events>`_
- `Example usage of events <https://github.com/debris/smart-exchange/blob/master/lib/contracts/SmartExchange.sol>`_
- `How to access them in js <https://github.com/debris/smart-exchange/blob/master/lib/exchange_transactions.js>`_