일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 스마트 컨트렉트 함수이름 중복
- Vue
- Vue.js
- git rebase
- 티스토리챌린지
- 오블완
- rust 기초
- 체인의정석
- ethers websocket
- SBT표준
- 러스트기초
- 스마트컨트렉트 함수이름 중복 호출
- ethers type
- nest.js설명
- 머신러닝기초
- 스마트컨트렉트프록시
- ethers v6
- 컨트렉트 동일한 함수이름 호출
- vue기초
- 스마트컨트렉트 예약어 함수이름 중복
- 스마트컨트렉트테스트
- chainlink 설명
- ambiguous function description
- 컨트렉트 배포 자동화
- multicall
- 러스트 기초 학습
- ethers typescript
- 러스트 기초
- 프록시배포구조
- ethers
- Today
- Total
체인의정석
Solidity에서 자주 만나는 에러 "CompilerError: Stack too deep, try removing local variables." 그리고 에러에 대한 해결 방안 정리 , 이벤트 로그와 함수 입력값 구조체로 개수 줄이기 본문
Solidity에서 자주 만나는 에러 "CompilerError: Stack too deep, try removing local variables." 그리고 에러에 대한 해결 방안 정리 , 이벤트 로그와 함수 입력값 구조체로 개수 줄이기
체인의정석 2022. 7. 13. 18:31스마트컨트렉트에서 이벤트 로그에 구조체를 가져와서 하나의 요소를 지정해준 것을 넣었더니 위와 같은 에러가 났다.
https://soliditydeveloper.com/stacktoodeep
찾아보니 솔리디티 개발자가 가장 싫어하는 직면하는 문제중 하나..
The reason is a limitation in how variables can be referenced in the EVM stack. While you can have more than 16 variables in it, once you try to reference a variable in slot 16 or higher, it will fail. It's therefore not always obvious why exactly some code is failing and then a few random changes just seem to fix it.
But I don't want to bore you with too much theory. This is supposed to be a practical blog post.
대충 변수가 16개 이상이면 이런 에러가 난다고 한다.
끔직하다..
아무튼 해결방법은 아래 5가지라고 한다.
1. Use less variables
2. Utilizing functions
3. Block scoping
4. Utilizing structs
5. Some Hacking
// SPDX-License-Identifier: MIT
pragma solidity 0.7.1;
contract StackTooDeepTest1 {
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;
}
}
예시 코드, 보다시피 엄청 많은 변수가 있는걸 볼 수있다.
이를 해결하기 위한 하나의 방법은
pragma solidity 0.7.1;
contract StackTooDeepTest1 {
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;
}
}
인터널 함수를 만들어서 각각 변수를 다른곳에 넘겨버리기
이건 이미 현재 코드에서 최적화를 진행하며 많이 해둔 상태이다.
// SPDX-License-Identifier: MIT
pragma solidity 0.7.1;
contract StackTooDeepTest2 {
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;
}
}
블록 스코프 만들기.
이런 방법도 되는 구나 싶지만 사실 저런식으로 짜는건 안정성이 없는거 같아서 선호하지 않는다.
// SPDX-License-Identifier: MIT
pragma solidity 0.7.1;
pragma experimental ABIEncoderV2;
contract StackTooDeepTest3 {
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;
}
}
구조체로 넘겨버리기 이건 따로 서치를 하다가 찾게 되었다.
함수의 입력값으로 변수가 너무 많이 나오면 이런 에러가 나는거 같은데 구조체로 한번에 들어와야 되는거 같다.
이것도 지금 코드에선 이미 적용이 되어 있는 상황이다.
msg.data 파싱하기
// SPDX-License-Identifier: MIT
pragma solidity 0.7.1;
contract StackTooDeepTest4 {
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 _fromUint(msg.data)+c+d+e+f+g+h+i;
}
function _fromUint(bytes memory data) internal pure returns(uint256 value) {
uint256 value1;
uint256 value2;
assembly {
value1 := mload(add(data, 36))
value2 := mload(add(data, 68))
value := add(value1, value2)
}
}
}
다 읽어봤는데
내가 작성한 코드에서 난 오류의 원인은 아무래도 변수를 너무 많이 선언했기 때문인거 같다.
가독성을 위해서 변수를 정의하고 그걸 가져와서 기록하는 식으로 하였는데
필요없는 변수는 최대한 제거하는 식으로 코드를 수정하였다.
그리고 나서 보니 이벤트 로그에 값이 많아서 다시한번 오류가 발생.
이벤트로 기록하는 변수를 줄이니까 역시 오류가 해결되었다.
그럼 구조체를 만들고 이벤트로그에 구조체를 기록시킨다면?
그결과 구조체가 이벤트 로그에 남으면서 오류가 해결되었다.
결국 변수 선언이 많을 시 에러가 나기 때문에 구조체를 활용해서 이런 부담을 줄이면 오류가 해결되고 이런 과정은 함수 뿐 만 아니라 이벤트에서도 작용함을 알 수 있었다.
오늘의 교훈 : 너무 많은 변수 선언은 좋지 않다. 변수 선언이 많을 경우 에러가 나게 되며 변수 선언을 최대한 줄여야 하고 이를 줄이기 위해서는 구조체를 만들어서 활용하는 방법을 사용하거나 최후의 경우 msg.Data를 사용하는것도 고려해봐야 겠다.
'블록체인 > Solidity' 카테고리의 다른 글
스마트컨트렉트에서 소수점 처리하는법과 엑셀에서 검산하는 방법 및 유의점 (0) | 2022.07.25 |
---|---|
Solidity 0.8.0 버전에서 HashStruct안에 UUID 넣는 법 (0) | 2022.07.21 |
이벤트 로그에 구조체 데이터 넣기, 이벤트 로그 작성하기 (0) | 2022.07.13 |
delegateCall에서의 상태변화 가능여부 및 사용하면 안되는 이유 (0) | 2022.07.08 |
DelegateCall에서 값을 가져오는 케이스 (0) | 2022.07.08 |