PageSourceSearch

https://hongchao.me/eth-event-logs/

html hongchao.me collected 2026-10-05 11:30:56 UTC 25,479 bytes, 344 lines download raw bytes

1<!DOCTYPE html>
2<html>
3  <head>
4    <title>Deep Dive into Ethereum Logs – Hongchao's Notes – sensing the abstract nonsense</title>
5
6        <meta charset="utf-8" />
7    <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
8    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
9    <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0'>
10
11    
12    <meta name="description" content="Logs in Ethereum are very useful since they are the underlying
13mechanism for events, which is the recommended way for smart contracts
14to communicate with the outside world. They also provide a
15significantly cheaper way to store data on-chain.
16
17
18
19
20" />
21    <meta property="og:description" content="Logs in Ethereum are very useful since they are the underlying
22mechanism for events, which is the recommended way for smart contracts
23to communicate with the outside world. They also provide a
24significantly cheaper way to store data on-chain.
25
26
27
28
29" />
30    
31    <meta name="author" content="Hongchao's Notes" />
32
33    
34    <meta property="og:title" content="Deep Dive into Ethereum Logs" />
35    <meta property="twitter:title" content="Deep Dive into Ethereum Logs" />
36    
37
38    <!--[if lt IE 9]>
39      
39<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
39
40    <![endif]-->
41
42    <link rel="stylesheet" type="text/css" href="/style.css" />
43    <link rel="alternate" type="application/rss+xml" title="Hongchao's Notes - sensing the abstract nonsense" href="/feed.xml" />
44
45    <!-- Created with Jekyll Now - http://github.com/barryclark/jekyll-now -->
46  </head>
47
48  <body>
49    <div class="wrapper-masthead">
50      <div class="container">
51        <header class="masthead clearfix">
52          <a href="/" class="site-avatar"><img src="https://hongchao.me/images/logo.jpg" /></a>
53
54          <div class="site-info">
55            <h1 class="site-name"><a href="/"><span class="hongchao">Hongchao's</span> <span class="notes">Notes</span></a></h1>
56            <p class="site-description">sensing the abstract nonsense</p>
57            <p class="fingerprint">E55D 0DFC 2B7D 7B95</p>
58          </div>
59
60          <nav>
61            <a href="/about">About</a>
62            <a href="https://alephium.org">Alephium</a>
63            <a href="https://bitcoin-decoder.softfork.se">Nioctib</a>
64          </nav>
65        </header>
66      </div>
67    </div>
68
69    <div id="main" role="main" class="container">
70      <article class="post">
71  <h1>Deep Dive into Ethereum Logs</h1>
72
73  <div class="entry">
74    <p>Logs in Ethereum are very useful since they are the underlying
75mechanism for events, which is the recommended way for smart contracts
76to communicate with the outside world. They also provide a
77significantly cheaper way to store data on-chain.
78<br />
79<br />
80<img src="/images/logs.png" alt="logs" style="width: 360px;" /></p>
81
82<p>As an example, the following code snippet from the
83<a href="https://github.com/Uniswap/v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/UniswapV2ERC20.sol#L60">UniswapV2ERC20.sol</a>
84contract emits a
85<a href="https://github.com/Uniswap/v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/UniswapV2ERC20.sol#L22">Transfer</a>
86event whenever a
87<a href="https://github.com/Uniswap/v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/UniswapV2ERC20.sol#L68">transfer</a>
88of tokens takes place.</p>
89
90<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">event</span> <span class="nx">Transfer</span><span class="p">(</span><span class="nx">address</span> <span class="nx">indexed</span> <span class="k">from</span><span class="p">,</span> <span class="nx">address</span> <span class="nx">indexed</span> <span class="nx">to</span><span class="p">,</span> <span class="nx">uint</span> <span class="nx">value</span><span class="p">);</span>
91
92<span class="kd">function</span> <span class="nx">_transfer</span><span class="p">(</span><span class="nx">address</span> <span class="k">from</span><span class="p">,</span> <span class="nx">address</span> <span class="nx">to</span><span class="p">,</span> <span class="nx">uint</span> <span class="nx">value</span><span class="p">)</span> <span class="kr">private</span> <span class="p">{</span>
93  <span class="nx">balanceOf</span><span class="p">[</span><span class="k">from</span><span class="p">]</span> <span class="o">=</span> <span class="nx">balanceOf</span><span class="p">[</span><span class="k">from</span><span class="p">].</span><span class="nx">sub</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
94  <span class="nx">balanceOf</span><span class="p">[</span><span class="nx">to</span><span class="p">]</span> <span class="o">=</span> <span class="nx">balanceOf</span><span class="p">[</span><span class="nx">to</span><span class="p">].</span><span class="nx">add</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
95  <span class="nx">emit</span> <span class="nx">Transfer</span><span class="p">(</span><span class="k">from</span><span class="p">,</span> <span class="nx">to</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
96<span class="p">}</span></code></pre></figure>
97
98<p>For a more detailed description of the Ethereum logs, including the
99concept of indexes/topics, data and cost, etc, highly recommend Luit
100Hollander’s excellent blog post <a href="https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba
10050378">Understanding event logs on the
101Ethereum
102blockchain</a>. This
103blog post will instead focus on how logs are actually implemented in Ethereum,
104specifically in <a href="https://geth.ethereum.org/">Geth</a>.</p>
105
106<p>When an event is emitted from a smart contract, one of the <a href="https://github.com/ethereum/go-ethereum/blob/b1e72f7ea998ad662166bcf23705ca59cf81e925/core/vm/opcodes.go#L198">LOG
107opcodes</a>
108will be generated by the smart contract compiler. Events can have
109maximum 4 topics/indexes, which is why there are 5 LOG opcodes (LOG0,
110LOG1, …, LOG4) defined. The
111<a href="https://github.com/Uniswap/v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/UniswapV2ERC20.sol#L22">Transfer</a>
112event in the above example has three indexes/topics in total: two
113explicit indexes <strong>from</strong> and <strong>to</strong>, and one implicit index which is
114the hash of the event signature (see Luit’s
115<a href="https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378">post</a>),
116in this case <strong>Transfer(address, address, uint)</strong>. As the result, the
117generated opscode is
118<a href="https://github.com/ethereum/go-ethereum/blob/b1e72f7ea998ad662166bcf23705ca59cf81e925/core/vm/opcodes.go#L202">LOG3</a>.</p>
119
120<p>LOG opcode is then interpreted by the <a href="https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L844">makeLog(size
121int)</a>
122function, which basically reads the indexes as well as a blob of
123arbitrary data from the stack, uses them to construct a
124<a href="https://github.com/ethereum/go-ethereum/blob/master/core/types/log.go#L31">log</a>
125object and then adds it to
126<a href="https://github.com/ethereum/go-ethereum/blob/master/core/state/statedb.go#L64">StateDB</a>. <strong>StateDB</strong>
127is an EVM data structure that stores anything within the merkle trie, and
128is the general query interface to retrieve contracts and
129accounts. It’s used to store data during transaction execution,
130including logs.</p>
131
132<figure class="highlight"><pre><code class="language-go" data-lang="go"><span class="k">func</span> <span class="n">makeLog</span><span class="p">(</span><span class="n">size</span> <span class="kt">int</span><span class="p">)</span> <span class="n">executionFunc</span> <span class="p">{</span>
133	<span class="k">return</span> <span class="k">func</span><span class="p">(</span><span class="n">pc</span> <span class="o">*</span><span class="kt">uint64</span><span class="p">,</span> <span class="n">interpreter</span> <span class="o">*</span><span class="n">EVMInterpreter</span><span class="p">,</span> <span class="n">scope</span> <span class="o">*</span><span class="n">ScopeContext</span><span class="p">)</span> <span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
134        <span class="c">// ... skip ...</span>
135		<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
136			<span class="n">addr</span> <span class="o">:=</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
137			<span class="n">topics</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">addr</span><span class="o">.</span><span class="n">Bytes32</span><span class="p">()</span>
138		<span class="p">}</span>
139
140        <span class="c">// ... skip ...</span>
141		<span class="n">interpreter</span><span class="o">.</span><span class="n">evm</span><span class="o">.</span><span class="n">StateDB</span><span class="o">.</span><span class="n">AddLog</span><span class="p">(</span><span class="o">&amp;</span><span class="n">types</span><span class="o">.</span><span class="n">Log</span><span class="p">{</span>
142			<span class="n">Address</span><span class="o">:</span> <span class="n">scope</span><span class="o">.</span><span class="n">Contract</span><span class="o">.</span><span class="n">Address</span><span class="p">(),</span>
143			<span class="n">Topics</span><span class="o">:</span>  <span class="n">topics</span><span class="p">,</span>
144			<span class="n">Data</span><span class="o">:</span>    <span class="n">d</span><span class="p">,</span>
145			<span class="c">// This is a non-consensus field, but assigned here because</span>
146			<span class="c">// core/state doesn't know the current block number.</span>
147			<span class="n">BlockNumber</span><span class="o">:</span> <span class="n">interpreter</span><span class="o">.</span><span class="n">evm</span><span class="o">.</span><span class="n">Context</span><span class="o">.</span><span class="n">BlockNumber</span><span class="o">.</span><span class="n">Uint64</span><span class="p">(),</span>
148		<span class="p">})</span>
149        <span class="c">// ... skip ...</span>
150	<span class="p">}</span>
151<span class="p">}</span></code></pre></figure>
152
153<p>When a transaction is executed using the
154<a href="https://github.com/ethereum/go-ethereum/blob/master/core/state_processor.go#L95">applyTransaction</a>
155function, the generated <a href="http://man.hubwiz.com/docset/Ethereum.docset/Contents/Resources/Documents/eth_getTransactionReceipt.html">transaction
156receipt</a>
157contains logs that are retreived from <strong>StateDB</strong> together with a
158bloom filter that statistically keeps track of all the topics of the
159log as well as the address of the contract that emits the logs. The
160reason to use a <a href="https://en.wikipedia.org/wiki/Bloom_filter">bloom
161filter</a> here is to strike
162a balance between query efficiency and storage space. If a user wants
163to search for logs with a set of topics, these topics can be run
164against the bloom filter to probabilistically determine if any log
165match the search criteria exist in this transaction receipt. False
166positives are removed by checking with the search criteria again.</p>
167
168<figure class="highlight"><pre><code class="language-go" data-lang="go"><span class="k">func</span> <span class="n">applyTransaction</span><span class="p">(</span><span class="n">msg</span> <span class="n">types</span><span class="o">.</span><span class="n">Message</span><span class="p">,</span> <span class="n">config</span> <span class="o">*</span><span class="n">params</span><span class="o">.</span><span class="n">ChainConfig</span><span class="p">,</span> <span class="n">bc</span> <span class="n">ChainContext</span><span class="p">,</span> <span class="n">author</span> <span class="o">*</span><span class="n">common</span><span class="o">.</span><span class="n">Address</span><span class="p">,</span> <span class="n">gp</span> <span class="o">*</span><span class="n">GasPool</span><span class="p">,</span> <span class="n">statedb</span> <span class="o">*</span><span class="n">state</span><span class="o">.</span><span class="n">StateDB</span><span class="p">,</span> <span class="n">blockNumber</span> <span class="o">*</span><span class="n">big</span><span class="o">.</span><span class="n">Int</span><span class="p">,</span> <span class="n">blockHash</span> <span class="n">common</span><span class="o">.</span><span class="n">Hash</span><span class="p">,</span> <span class="n">tx</span> <span class="o">*</span><span class="n">types</span><span class="o">.</span><span class="n">Transaction</span><span class="p">,</span> <span class="n">usedGas</span> <span class="o">*</span><span class="kt">uint64</span><span class="p">,</span> <span class="n">evm</span> <span class="o">*</span><span class="n">vm</span><span class="o">.</span><span class="n">EVM</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="n">types</span><span class="o">.</span><span class="n">Receipt</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
169    <span class="c">// ... skip ...</span>
170
171	<span class="c">// Set the receipt logs and create the bloom filter.</span>
172	<span class="n">receipt</span><span class="o">.</span><span class="n">Logs</span> <span class="o">=</span> <span class="n">statedb</span><span class="o">.</span><span class="n">GetLogs</span><span class="p">(</span><span class="n">tx</span><span class="o">.</span><span class="n">Hash</span><span class="p">(),</span> <span class="n">blockHash</span><span class="p">)</span>
173	<span class="n">receipt</span><span class="o">.</span><span class="n">Bloom</span> <span class="o">=</span> <span class="n">types</span><span class="o">.</span><span class="n">CreateBloom</span><span class="p">(</span><span class="n">types</span><span class="o">.</span><span class="n">Receipts</span><span class="p">{</span><span class="n">receipt</span><span class="p">})</span>
174	<span class="n">receipt</span><span class="o">.</span><span class="n">BlockHash</span> <span class="o">=</span> <span class="n">blockHash</span>
175	<span class="n">receipt</span><span class="o">.</span><span class="n">BlockNumber</span> <span class="o">=</span> <span class="n">blockNumber</span>
176
177    <span class="c">
177// ... skip ...</span>
178<span class="p">}</span></code></pre></figure>
179
180<p>When a block is created in the
181<a href="https://github.com/ethereum/go-ethereum/blob/master/core/types/block.go#L198">NewBlock</a>
182function, it creates a bloom filter in the block header which
183essentially combines the bloom filters of all the transaction receipts
184included in this block. This allows quick check of whether any logs
185with matching criteria exists in this block.</p>
186
187<figure class="highlight"><pre><code class="language-go" data-lang="go"><span class="k">func</span> <span class="n">NewBlock</span><span class="p">(</span><span class="n">header</span> <span class="o">*</span><span class="n">Header</span><span class="p">,</span> <span class="n">txs</span> <span class="p">[]</span><span class="o">*</span><span class="n">Transaction</span><span class="p">,</span> <span class="n">uncles</span> <span class="p">[]</span><span class="o">*</span><span class="n">Header</span><span class="p">,</span> <span class="n">receipts</span> <span class="p">[]</span><span class="o">*</span><span class="n">Receipt</span><span class="p">,</span> <span class="n">hasher</span> <span class="n">TrieHasher</span><span class="p">)</span> <span class="o">*</span><span class="n">Block</span> <span class="p">{</span>
188    <span class="c">// ... skip ...</span>
189
190	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">receipts</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>
191		<span class="n">b</span><span class="o">.</span><span class="n">header</span><span class="o">.</span><span class="n">ReceiptHash</span> <span class="o">=</span> <span class="n">EmptyRootHash</span>
192	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
193		<span class="n">b</span><span class="o">.</span><span class="n">header</span><span class="o">.</span><span class="n">ReceiptHash</span> <span class="o">=</span> <span class="n">DeriveSha</span><span class="p">(</span><span class="n">Receipts</span><span class="p">(</span><span class="n">receipts</span><span class="p">),</span> <span class="n">hasher</span><span class="p">)</span>
194		<span class="n">b</span><span class="o">.</span><span class="n">header</span><span class="o">.</span><span class="n">Bloom</span> <span class="o">=</span> <span class="n">CreateBloom</span><span class="p">(</span><span class="n">receipts</span><span class="p">)</span>
195	<span class="p">}</span>
196
197    <span class="c">// ... skip ...</span>
198<span class="p">}</span></code></pre></figure>
199
200<p>When a block is persisted using
201<a href="https://github.com/ethereum/go-ethereum/blob/master/core/blockchain.go#L1175">writeBlockWithState</a>
202function, it persists all transaction receipts with logs per
203block. The
204<a href="https://github.com/ethereum/go-ethereum/blob/master/core/rawdb/schema.go#L88">format</a>
205of the key value pair is <strong>blockReceiptsPrefix + num (uint64 big endian) + hash -&gt; block receipts</strong>.</p>
206
207<figure class="highlight"><pre><code class="language-go" data-lang="go"><span class="k">func</span> <span class="p">(</span><span class="n">bc</span> <span class="o">*</span><span class="n">BlockChain</span><span class="p">)</span> <span class="n">writeBlockWithState</span><span class="p">(</span><span class="n">block</span> <span class="o">*</span><span class="n">types</span><span class="o">.</span><span class="n">Block</span><span class="p">,</span> <span class="n">receipts</span> <span class="p">[]</span><span class="o">*</span><span class="n">types</span><span class="o">.</span><span class="n">Receipt</span><span class="p">,</span> <span class="n">logs</span> <span class="p">[]</span><span class="o">*</span><span class="n">types</span><span class="o">.</span><span class="n">Log</span><span class="p">,</span> <span class="n">state</span> <span class="o">*</span><span class="n">state</span><span class="o">.</span><span class="n">StateDB</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
208    <span class="c">
208// ... skip ...</span>
209
210	<span class="n">rawdb</span><span class="o">.</span><span class="n">WriteBlock</span><span class="p">(</span><span class="n">blockBatch</span><span class="p">,</span> <span class="n">block</span><span class="p">)</span>
211	<span class="n">rawdb</span><span class="o">.</span><span class="n">WriteReceipts</span><span class="p">(</span><span class="n">blockBatch</span><span class="p">,</span> <span class="n">block</span><span class="o">.</span><span class="n">Hash</span><span class="p">(),</span> <span class="n">block</span><span class="o">.</span><span class="n">NumberU64</span><span class="p">(),</span> <span class="n">receipts</span><span class="p">)</span>
212	<span class="n">rawdb</span><span class="o">.</span><span class="n">WritePreimages</span><span class="p">(</span><span class="n">blockBatch</span><span class="p">,</span> <span class="n">state</span><span class="o">.</span><span class="n">Preimages</span><span class="p">())</span>
213
214    <span class="c">// ... skip ...</span>
215<span class="p">}</span></code></pre></figure>
216
217<p>There are a few ways to consume the emmited events. After a
218transaction is mined into the blockchain,
219<a href="https://eth.wiki/json-rpc/API#eth_gettransactionreceipt">eth_getTransactionReceipt</a>
220can be called with the transaction hash to get the <a href="https://eth.wiki/json-rpc/API#eth_getfilterchanges">transaction
221receipt</a>, which
222contains a <code class="language-plaintext highlighter-rouge">logs</code> field that carries an array of log objects that this
223transaction generated. DApp frontends can also leverage the
224combination of the
225<a href="https://eth.wiki/json-rpc/API#eth_newfilter">eth_newFilter</a> and
226<a href="https://eth.wiki/json-rpc/API#eth_getfilterchanges">eth_getFilterChanges</a>
227method to poll the new events of interest. Web3.js abstracts this away
228by providing the
229<a href="https://web3js.readthedocs.io/en/v1.2.11/web3-eth-subscribe.html#subscribe-logs">subscribe(“log”)</a>
230method to help real time consumption of the incoming logs using the
231subscription model.</p>
232
233<p>Let’s look at these JSON-RPCs in more details:</p>
234<ul>
235  <li><a href="https://eth.wiki/json-rpc/API#eth_gettransactionreceipt">eth_getTransactionReceipt</a>.
236Return the transaction receipt for a transaction id. Since
237transaction receipts are stored per block, this basically
238<a href="https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L1615">fetches all the receipts for the
239block</a>
240that this transaction belongs to and only return the requested
241one. As mentioned before, logs are part of the transaction receipt.</li>
242  <li><a href="https://eth.wiki/json-rpc/API#eth_newfilter">eth_newFilter</a> &amp;
243<a href="https://eth.wiki/json-rpc/API#eth_getfilterchanges">eth_getFilterChanges</a>.
244Return logs that match the search criteria such as the block range,
245contract address as well as topics. This leverages the bloom filter
246both in the block header as well as in the transaction receipt to
247determine which logs should be returned. False positives are
248filtered again using the search criteria. The filter logic can be found
249<a href="https://github.com/ethereum/go-ethereum/blob/master/eth/filters/filter.go#L119">here</a>. There
250are also some <a href="https://github.com/ethereum/go-ethereum/blob/master/eth/filters/filter.go#L153">index
251optimization</a>
252so that it doesnt have to iterate through each blocks in the block
253range while searching for the matching logs.</li>
254</ul>
255
256<p>Hope this blog post has shed some light on how logging is implemented
257Ethereum. The overall design feels pretty elegant and efficient. One
258tradeoff here is how much data should be indexed on-chain v.s
259off-chain. Ethereum decided to have max 4 topics per log, perhaps a
260good balance between searchability and storage, but one can make an
261legitimate argument that indexes should be pushed more to the
262application layer since data is more understood there and it is easier
263to make changes afterwards.</p>
264
265<p><br /></p>
266
267<hr />
268
269<p>Reference:</p>
270<ul>
271  <li><a href="https://ethereum.org/ig/developers/tutorials/logging-events-smart-contracts/">Logging data from smart contracts with events</a></li>
272  <li><a href="https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378">Understanding event logs on the Ethereum blockchain</a></li>
273  <li><a href="https://ethereum.stackexchange.com/questions/3418/how-does-ethereum-make-use-of-bloom-filters/3426">How does Ethereum make use of bloom filters?</a></li>
274  <li><a href="https://consensys.net/blog/developers/guide-to-events-and-logs-in-ethereum-smart-contracts">A guide to events and logs in ethereum smart contracts</a></li>
275  <li><a href="https://medium.com/remix-ide/the-anatomy-of-a-transaction-receipt-d935aacc9fcd">The Anatomy of a Transaction Receipt</a></li>
276</ul>
277
278  </div>
279
280  <div class="date">
281    Written on January 22, 2022
282  </div>
283
284  
285<div class="comments">
286	<div id="disqus_thread"></div>
287	
287<script type="text/javascript">
288
289	    var disqus_shortname = 'hcslearningnotes';
290
291	    (function() {
292	        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
293	        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
294	        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
295	    })();
296
297	</script>
297
298	<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
299</div>
300
301</article>
302
303    </div>
304
305    <div class="wrapper-footer">
306      <div class="container">
307        <footer class="footer">
308          
309
310
311
312<a href="https://github.com/h0ngcha0"><i class="svg-icon github"></i></a>
313
314<a href="https://www.linkedin.com/in/liuhongchao"><i class="svg-icon linkedin"></i></a>
315
316<a href="/feed.xml"><i class="svg-icon rss"></i></a>
317<a href="https://www.twitter.com/hongchao"><i class="svg-icon twitter"></i></a>
318
319
320
321
322        </footer>
323      </div>
324    </div>
325
326    
327	<!-- Google Analytics -->
328	
328<script>
vendor: 339 bytes, lines 328-334
328
329		(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
330		(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
331		m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
332		})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
333
334		ga('create', '
334UA-54771594-1
vendor: 14 bytes, lines 334-335
334', 'auto');
335		
335ga('send', 'pageview', {
336		  'page': '/eth-event-logs/',
337		  'title': 'Deep Dive into Ethereum Logs'
338		});
339	</script>
339
340	<!-- End Google Analytics -->
341
342
343  </body>
344</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.