block 전역 변수와 시간
Solidity 에는 호출이나 블록의 정보를 담은 전역 변수(global variables)가 있습니다.
이 중 block 과 msg 는 컨트랙트 로직에서 특히 자주 쓰입니다.
선언 없이 어디서나 바로 읽을 수 있고, 값은 EVM 이 실행 시점에 채워 줍니다.
block 전역 변수
block 에는 현재 트랜잭션이 담긴 블록의 정보가 들어 있습니다.
| 표현식 | 의미 |
|---|---|
block.timestamp | 현재 블록의 Unix 타임스탬프(초 단위) |
block.number | 현재 블록 번호 |
block.chainid | 현재 체인의 ID (예: 이더리움 메인넷 = 1) |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract BlockInfo {
function currentTime() public view returns (uint256) {
return block.timestamp;
}
function currentBlock() public view returns (uint256) {
return block.number;
}
function chainId() public view returns (uint256) {
return block.chainid;
}
}block.timestamp 는 초 단위로 시간을 비교할 때, block.number 는 몇 블록이 지났는지로 기간을
잴 때 씁니다. block.chainid 는 멀티체인 환경에서 다른 체인의 서명이 재사용(replay)되지 않는지
확인할 때 쓰입니다.
msg 전역 변수 복습
| 표현식 | 의미 |
|---|---|
msg.sender | 현재 함수를 호출한 주소 |
msg.value | 함수 호출과 함께 보낸 Ether 의 양 (wei 단위) |
msg.sender 는 접근 제어(예: onlyOwner)에, msg.value 는 결제 로직에 핵심적으로 쓰입니다.
시간 기반 로직
block.timestamp 를 이용하면 "마감 시간이 지났는가?", "잠금 기간이 끝났는가?" 같은
시간 조건을 만들 수 있습니다. 보통 배포 시점에 기준 시각을 저장해두고, 나중에 현재 시각과 비교합니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract TimeLock {
uint256 public unlockTime;
constructor(uint256 lockSeconds) {
unlockTime = block.timestamp + lockSeconds; // 지금부터 lockSeconds 초 뒤
}
function isUnlocked() public view returns (bool) {
return block.timestamp >= unlockTime;
}
}지분증명(PoS) 전환 이후 이더리움의 블록은 12초 슬롯마다 만들어지고, block.timestamp 는 그
슬롯 시각에 거의 고정됩니다. 즉 제안자가 초 단위로 값을 주무르지는 못하는 대신, 다음 블록의
타임스탬프가 미리 예측 가능 합니다. 따라서 block.timestamp 를 난수원으로 쓰면 공격자가
결과를 미리 계산할 수 있으므로, 도박·추첨처럼 예측 불가능성이 필요한 로직에는 절대 쓰면 안 됩니다.
반면 며칠·몇 주 단위의 잠금처럼 거친 시간 비교에는 안전하게 사용할 수 있습니다.
Solidity 는 1 days, 1 weeks 같은 시간 단위 리터럴을 제공합니다. block.timestamp + 7 days
처럼 쓰면 초 단위 계산 실수를 줄일 수 있습니다.
아래 에디터에서 배포 시각을 기록하는 컨트랙트를 직접 컴파일해보세요. Run 을 누르면 됩니다.