EIP-150: Gas cost changes for IO-heavy operations

frenchkebab·2023년 5월 13일
0

EIP / Open Source

목록 보기
6/9

EIP-150

참고

1. External Call과 gas에 대한 이해

external call이 발생하면 (CALL, STATICCALL, DELEGATECALL) 해당 externall call에서 사용되기 위한gas가 전달되게 된다.

value를 설정하듯이 전달할 gas또한 caller가 설정할 수도 있다.

참고로 CALL opcode를 사용하게 되면 무조건 21000 gas는 소모하여 날아가게 된다.

2. EIP-150의 제안 배경

1) 명륜 진사 CALL

머나 먼 옛날에는 CALL의 gas cost가 매우 적었고, 모든 gas를 전달할 수 있었다.

따라서 거의 무한히 call stack을 쌓을 수 있었다.

2) Stack depth를 1024로 제한

"stack too deep" 문제를 해결하기 위해서, stack의 깊이를 1024로 제한하게 되었다.
(현재도 이것은 유지되고 있다.)

stack의 깊이가 1024까지 도달되면 revert가 나게 되었다.

3) Call Depth Attack

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.5;

// DO NOT USE!!!
contract Auction {
    address highestBidder;
    uint256 highestBid;

    function bid() external payable {
        if (msg.value < highestBid) revert();

        if (highestBidder != address(0)) {
            payable(highestBidder).send(highestBid); // refund previous bidder
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
    }
}

공격자가 bid() 함수를 호출하기 전에, 스스로에게 recursive call을 돌려서 1023개의 call stack을 쌓아놓고,
1024번 째에 bid()를 호출한다.

그럼 send의 경우 조용히 revert가 나게 되고 코드는 마지막까지 흘러간다.
(전체 트랜잭션 롤백이 일어나지 않아 이전 highestBidder는 환불을 받지 못하게 된다.)

EIP-150

요약해서 말하자면, call opcode를 사용할 때 (call stack이 한 칸 늘어날 때) 현재 사용할 수 있는 gas의 63/64 만큼만 전달할 수 있다.

Gas available at Stack depth 0  = Initial gas available * (63/64)^0
Gas available at Stack depth 1  = Initial gas available * (63/64)^1
Gas available at Stack depth 2  = Initial gas available * (63/64)^2
Gas available at Stack depth 3  = Initial gas available * (63/64)^3
.
.
.
Gas available at Stack depth N  = Initial gas available * (63/64)^N

이렇게 external call로 콜 스택이 하나씩 늘어날 때마다 gasleft(63/64)*N 만큼씩만 가스를 소모할 수 있는 것이다.
(명시적으로 gasleft를 전달해 주더라도, 1/64는 caller에게 남게 된다.)

이렇게 call stack이 늘어날 떄마다 급격하게 callee가 사용할 수 있는 gas의 양은 줄어들게 된다.

EIP-150 이후로 사실상 불가능하지만, 이론적으로 EVM에서는 여전히 1024개의 stack이 허용된다.

결론

EIP-150Call Depth Attack을 막기 위해 제안되었으며, 이는 63/64 Rule을 통해서 이루어진다.

참고로 위에서 언급하였듯, call 사용 시에 명시적으로 gas left를 모두 전달해 주어도 여전히 gas left1/64Caller contract에 남아있게 된다.

profile
Solidity에 대해 공부하고 있습니다.

0개의 댓글