Total gas is really smaller in using memory?

Total gas is really smaller in using memory?

Magic Dragon Dao의 컨트랙트를 스터디하던 중 removeZeroStakes 함수에서 이상한점을 발견했다. for loop 내부의 struct Stake 타입의 변수 s가 storage 키워드로 표시되어 있었다. 아래 s.amount에서 값을 읽어오는 부분 외에는 쓰이는 부분이 없으니 당연히 체인에 기록되는 storage가 아닌 memory를 써야 gas 소모량을 줄일 수 있지 않을까? (Q)

    function _removeZeroStakes() internal {
        bool shouldRecurse = stakes.length > 0;

        for (uint256 i = 0; i < stakes.length; i++) {
            _updateStakeDepositAmount(i);

            Stake storage s = stakes[i]; // here!!!

            if (s.amount == 0) {
                _removeStake(i);
                // Stop looping and start again - we will skip
                // out of the look and recurse
                break;
            }

            if (i == stakes.length - 1) {
                // We didn't remove anything, so stop recursing
                shouldRecurse = false;
            }
        }

        if (shouldRecurse) {
            _removeZeroStakes();
        }
    }

더 공부를 하고 난 뒤에 얻어내 위 Q의 정답은 “항상 그런것은 아니다” 이다.

솔리디티에서 memory 참조 변수에 storage 참조 변수를 어사인(=)하면, 메모리 공간을 확보하기 위한 추가적인 gas를 지불해야한다. 즉, 변수에 access 할 떄 마다 SLOAD보다 코스트가 낮은 MLOAD를 사용할 수 있지만, 메모리 할당을 위한 코스트가 추가적으로 지출된다.

반대로, storage 참조 변수로 선언하면, 메모리 할당과 관련된 코스트는 없고 한 번의 SLOAD만 실행하면 된다.

일반적으로 4번의 변수 access 까지는 storage로 선언하는게 좋고, 그 보다 많은 수의 access가 예상될 때에는 memory 로 변수를 선언하는것이 좋다고 한다. [1]

위 예제에서는 한 번의 access만 있기때문에 Stake storage s 로 해주는게 이제는 맞아보인다.

[1] https://ethereum.stackexchange.com/questions/66382/switching-from-storage-to-memory-increases-the-gas-cost