Logs in EVM
The LOG opcode in EVM is a powerful tool for logging and debugging smart contracts. It allows developers to log events and data within their contracts, which can be helpful in tracking the execution of the contract.
Typically a contract emits an event as a result of some action, as a notification. This does not change any internal variable but the state of the blockchain since events are stored as transaction logs.
Ethereum has 5 opcodes dedicated to emitting events, written LOG0
to LOG4
, that write an event with 0 to 4 topics. The gas cost is different for each opcode since each opcode effectively stores additional information on the blockchain that is permanently accessible.
What is a Topic?
A topic in an event is a 32-byte identifier that categorizes the event. Topics allow for the categorization and filtering of events, making it easier to search for specific events within a smart contract.
When a contract logs an event, it can specify up to four topics, which can be 32-byte values. The topics are used to categorize the event, and they can be used to filter events in client-side applications or Ethereum clients.
Each log record consists of both topics and data.
The first topic usually consists of the signature (a keccak256 hash) of the name of the event that occurred, including the types (uint256, string, etc.) of its parameters.
What is Data?
The second part of a log record consists of additional data. but there are differences, as topics are searchable while data are not. But, including data is a lot cheaper than including topics.
However, topics are limited to 4 * 32 bytes, and event data is not, which means it can include large or complicated data like arrays or strings.
It's important to note that the LOG opcode is not a function and is not executed by the contract's logic. Instead, it's a low-level instruction that can be used to log data to the blockchain.
Does it make sense?
Let's take an example of the "Transfer(address,address,uint256)" event of ERC20 for the "_mint()" function.
As we are using here LOG3 opcode that means it will require 5 params to log an event. "LOG3(offset, size, topic1, topic2, topic3)".
The first param "offset" is the byte offset in memory, you can think of it as an index in memory, and the next param "size" is the length of data to start copying from 'offset". In layman's terms here we are doing memory[offset: offset + size], this is the additional data of the log.
Now the next three params are topics, now how are we sure the event below needs three topics?
Since the first 2 arguments are declared as indexed, they are treated like additional topics, which means the event opcode must contain 3 topics, the first being the event signature, and the rest two being the indexed params "from" and "to".
As the "_mint()" function has "from" address as "address(0)", I have stored both "from" and "to" in memory and used "mload" to load these into the stack for LOG3 opcode.
What about gas usage?
The gas for logging the event is equal to the"375 * (n + 1) + 8 * b
", where `n` is the number of topics, and `b` is the number of bytes of its data.
That's pretty cheap, right? Let's talk about an ERC20 Transfer event gas.
Transfer event consists of 3 topics that mean 375 * 3 = 1125 gas, now 8 gas for each byte of data. As the data only contains the value "amount" that will take only 32 bytes, which means 8 * 32 = 256 gas for the data logging operation.
This adds up to a total gas cost of 1756 gas if we assume the gas price to be 50gwei the total operation cost will be 87800 Gwei. if the current price (1500$) of ETH is considered then you only need to pay 0.13$.
Now you can see that logs are the easiest way to store tiny amounts of data on the Ethereum blockchain for a small price.
But how EVM stores those logs? Does it use a different data structure for it? Well, that's the topic for another blog!
I hope you enjoyed it, Thanks for the read!