Ethereum: Event, Log
ERC20 등 토큰 스마트 컨트랙트에서 토큰이 전송되면 Transfer 이벤트가 발생한다.
이더리움의 Event 는 단순히 상태 변화를 기록하는 메커니즘이 아니다.
온체인과 오프체인을 연결하는 인터페이스이기도 하다. (스토리지에 저장하는 것보다 저렴한)
Log in Ethereum
이더리움 트랜잭션의 타입을 보면 “log” 필드가 있다.
Log 는 이더리움 트랜잭션 실행 중 발생하는 이벤트를 기록하는 데이터 구조이다.
State 가 아니기 때문에 Transaction Receipt 에 저장된다.
Solidity에서 Event는 다음과 같이 선언하고 사용한다.
-
Event 선언:
event Transfer(address indexed from, address indexed to, uint256 value); -
Event 발생:
emit Transfer(msg.sender, recipient, amount);
Event 선언에는 이벤트 이름과 파라미터 목록이 포함된다.
Event를 발생시킬 때는 emit 키워드를 사용한다. Solidity 0.4.21 이전 버전에서는 emit 없이 이벤트 이름만 호출했지만, 현재는 명시적으로 emit을 사용하는 것이 권장된다.
이렇게 발생한 이벤트는 트랜잭션 영수증에 로그로 기록되며, 외부 클라이언트는 이를 수신하고 처리할 수 있다.
Indexed 파라미터
Event 파라미터에 indexed 키워드를 붙이면 해당 값이 topic으로 저장되어 검색 가능한 필드가 된다. 이는 데이터베이스의 인덱스와 유사한 개념이다.
최대 3개 까지만 가능하고, 동적 타입 (string, bytes, 배열 등)은 원본 값 대신 keccak256 해시가 저장된다.
예를 들어 ERC-20의 Transfer 이벤트는 from과 to를 indexed로 지정한다.
event Transfer(address indexed from, address indexed to, uint256 value);
Topics vs Data
Log는 내부적으로 두 가지 주요 구성 요소로 이루어진다: topics와 data.
Topics 배열
-
최대 4개의 32바이트 요소를 담을 수 있는 배열이다
-
Topic[0]은 일반적으로 이벤트 시그니처의 keccak256 해시가 저장된다
-
Topic[1], Topic[2], Topic[3]에는 indexed 파라미터의 값이 저장된다
-
따라서 indexed 파라미터는 최대 3개까지 가능하다(topic[0]은 시그니처가 차지)
-
Topics는 블록 헤더의 Bloom Filter에 포함되어 빠른 검색이 가능하다
Data 필드
-
Indexed가 아닌 모든 파라미터가 ABI 인코딩되어 저장된다
-
가변 길이이며, 크기에 제한이 없다(가스 비용의 제약만 있음)
-
검색을 위한 인덱싱은 되지 않으며, 로그를 가져온 후 디코딩해야 읽을 수 있다
-
Topics보다 저장 비용이 저렴하다
보통 Topics와 Data의 선택 기준은 다음과 같다.
-
검색 필요성: 필터링이 필요한 필드는 indexed로 지정
-
데이터 크기: 큰 데이터는 data 필드에 저장(문자열, 배열 등)
-
가스 최적화: indexed가 많을수록 가스 비용 증가, 필요한 것만 indexed로 지정
Transaction Receipt 구조
Transaction Receipt 에는 다음과 같은 정보가 포함된다.
-
status: 트랜잭션 성공(1) 또는 실패(0) 여부 -
cumulativeGasUsed: 블록 내에서 이 트랜잭션까지 사용된 누적 가스 -
gasUsed: 이 트랜잭션이 실제로 소비한 가스 -
effectiveGasPrice: 실제로 지불한 가스 가격(base fee + priority fee) -
transactionHash: 트랜잭션의 해시 -
transactionIndex: 블록 내 트랜잭션 순서 -
blockHash: 트랜잭션이 포함된 블록의 해시 -
blockNumber: 블록 번호 -
from: 트랜잭션 발신자 -
to: 트랜잭션 수신자(컨트랙트 생성 시 null) -
contractAddress: 컨트랙트 생성 시 새로 생성된 컨트랙트 주소
Log 관련 필드
-
logs: Log 객체의 배열 -
logsBloom: Bloom filter (256 바이트)
각 Log 객체는 다음 구조를 갖는다.
-
address: 로그를 생성한 컨트랙트 주소 -
topics: 32바이트 해시의 배열(최대 4개) -
data: 추가 데이터가 담긴 바이트 배열 -
blockNumber: 블록 번호 -
transactionHash: 트랜잭션 해시 -
transactionIndex: 블록 내 트랜잭션 인덱스 -
blockHash: 블록 해시 -
logIndex: 블록 내 로그의 순서 -
removed: 체인 재구성으로 제거되었는지 여부