티스토리 뷰

여러 기능을 넣는데 갑자기 이런 에러가 떴다.

"CompilerError: Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true`
... Otherwise, try removing local variables."

 

다행히 다들 겪는 일이었다

고통은 나누면 반이된다,,

에러의 이유

EVM 스택에는 16 variable 밖에 못올라간다. 이 variable 은 input and output arguments 모두를 포함한다-> 너무나 황당

정확히는 16슬랏이긴한데, 보통 1슬랏 1 variable 쓰니까....

이제 취향껏 고쳐보자

 

해결법

1. variable 갯수 줄이기 ㅋㅋ

2. internal function 쓰기 ( 실행 다 되면 메모리가 해제되니까 ㅇㅇ )

3. block scoping

4. struct 활용하기

 

예를들면 이런 문제코드가 있다. 이 코드를 1~4번방식으로 고쳐보자.

contract StackTooDeepTest {
    function addUints(
        uint256 a,uint256 b,uint256 c,uint256 d,uint256 e,uint256 f,uint256 g,uint256 h,uint256 i
    ) external pure returns(uint256) {
        
        return a+b+c+d+e+f+g+h+i;
    }
}

에러나는이유: 로컬변수가 너무많아서

-> 여기 이해가안감 로컬변수 a~i 까지 9개에 리턴시 1개 추가 해서 10개아닌가?

return 내의 객체가 하나씩 다르게 잡혀서 18개로 잡히나?

 

1. 이경우 variable 갯수를 더 줄일수 없다.

2. internal function 쓰기

contract StackTooDeepTest {
   function addUints(
        uint256 a,uint256 b,uint256 c,uint256 d,uint256 e,uint256 f,uint256 g,uint256 h,uint256 i
    ) external pure returns(uint256) {
        
        return _addThreeUints(a,b,c) + _addThreeUints(d,e,f) + _addThreeUints(g,h,i);
    }
    
    function _addThreeUints(uint256 a, uint256 b, uint256 c) private pure returns(uint256) {
        return a+b+c;
    }
}

이렇게 더하는 함수를 새로 만들면

a~i까지 9개에 리턴에 로컬변수 3개로 잡혀서 총 12개로 잡히는 것 같다.

기능따라 펑션을 분리하는 것은 좋은 습관이므로 좋은 코딩법에도 기여한다.

 

3. block scoping

uniswap 에서 쓴방법

contract StackTooDeepTest {
    function addUints(
        uint256 a,uint256 b,uint256 c,uint256 d,uint256 e,uint256 f,uint256 g,uint256 h,uint256 i
    ) external pure returns(uint256) {
        
        uint256 result = 0;
        
        {
            result = a+b+c+d+e;
        }
        
        {
            result = result+f+g+h+i;
        }

        return result;
    }
}

js 의 block scoping 과 같아보인다.

Block scoped variables: A block scoped variable means that the variable defined within a block will not be accessible from outside the block. A block can reside inside a function, and a block scoped variable will not be available outside the block even if the block is inside a function.

 

이러면 처음 로컬변수 9개

result 까지 10개

result = a+b+c+d+e; 때 총 15개

첫번째 block scope 가 끝나면 다시 10개

두번째 block scope 안에서 14개

두번째 scope 끝나면 다시 10개...

이런식으로 관리가 가능하다.

 

함수로 분리하기 애매할때 사용하면 좋아보임

 

4. Use Structs

객체를 쓰자 객체

contract StackTooDeepTest {
    struct UintPair {
        uint256 value1;
        uint256 value2;
    }
    
    function addUints(
        UintPair memory a, UintPair memory b, UintPair memory c, UintPair memory d, uint256 e
    ) external pure returns(uint256) {
        
        return a.value1+a.value2+b.value1+b.value2+c.value1+c.value2+d.value1+d.value2+e;
    }
}

a~i 까지 변수 9개가

변수 a~e 5개로 줄었다.

이게 작동한다는 것은 return 때도 객체가 struct 채로 메모리가 할당됨을 알수있다.

 

 

 

근데

이렇게 평화롭게끝나면

솔리디티가

아니지

 

만약 16 slot 변수까지 된다면..

이런코드도 되어야한다.

 

contract TestStackError {

  event LogValue(uint);

  function logArg(
    uint a1, uint a2, uint a3, uint a4,
    uint a5, uint a6, uint a7, uint a8,
    uint a9, uint a10, uint a11, uint a12,
    uint a13, uint a14, uint a15, uint a16
  ) public {
    emit LogValue(a16);
  }
}

인풋 아규먼트가 16개잖아

되야맞다 ㅇㅇ

근데 결과는?

ptsd 담당

한참찾아보니

이게 오랜 에러였고 

솔리디티 버전 0.8.13 부터 IR 파이프라인을 개선함으로서 고쳤다고 주장했다.

출처1  출처2

 

고쳤다고 하니 실제로 옵션을 바꾸라는대로 바꿔보자.

빌드 고고고

안돼

이 에러 6월에 고치고있었잖아.. 이후에 솔리디티 버전도 업데이트 됐잖아.. 왜 이 에러는 아직도 fix 가 안됐어..?

하여튼 에러고쳐질때까지 16개 slot 꽉채워 못쓴다가 결론이다

 

 

 

출처

https://soliditydeveloper.com/stacktoodeep

https://medium.com/coinmonks/stack-too-deep-error-in-solidity-608d1bd6a1ea

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함