feat(week-03): complete week-03 assignment#34
feat(week-03): complete week-03 assignment#34sweatbuckets wants to merge 6 commits intoBay-17th:mainfrom
Conversation
리뷰개발 과제VaultSecure.sol - ReentrancyGuard + CEI 패턴 둘 다 적용한 거 아주 좋습니다!! Week-02 SimpleStorage도 deposit/withdraw 정확하고, NatSpec 주석에 본인 이해를 덧붙인 것 좋습니다. 퀴즈Week-02 퀴즈 10/10 정확합니다. Week-03 퀴즈 10/10 정확합니다. 몇 가지 참고:
배운 점receive() 함수를 통한 재진입 공격 메커니즘 이해가 매우 깊습니다. 질문 답변
맞습니다.... 제가 테스트 작성에 실수를 한 것 같습니다... ㅠ 문제 원인: receive()에서 vault.withdraw()가 revert → receive() revert → call returns false → require(success) revert → 첫 번째 withdraw까지 전체 롤백 수정 내용: Attacker의 receive()에 try/catch 추가해서 revert 전파를 막았습니다. |
과제 제출 정보
주차: Week <03>
과제 유형:
구현 내용
배운 점 (What I Learned)
이번 주에 배운 것 (2-3가지)
어려웠던 점과 해결 방법
어려웠던 점:
외부 함수를 호출하는 서로 다른 여러 함수가 하나의 함수에 담길 경우, 이 트랜잭션의 실행만으로 무수히 많은 상태를 변경할 수 있을 텐데 트랜잭션 단위의 원자성을 보장하는 EVM에서 이를 막지 않아도 되는지, 이처럼 예측이 어렵고 복잡도가 높은 트랜잭션이 시스템의 위협이 되진 않는지 의문이 들었다.
해결 방법:
하나의 트랜잭션이 복잡한 상태 변경을 유발하더라도 그에 상응하는 가스 비용이 청구되므로 EVM에게는 트랜잭션 개수 자체는 연산 복잡도와 논리적으로 관계없음을 알게 됐다. 다만 각 블록마다 포함될 수 있는 총 가스량 한도가 약 30,000,000 gas(이더리움 메인넷)로 이론상 트랜잭션의 연산 제한은 존재한다. 이보다 적다면 아무리 복잡한 연산이라도 그에 준하는 가스비용을 내고 실행하는 것을 시스템에서 막지 않는다는 것을 이해했다.
질문 사항
Vault.t.sol의 Attacker에서 현재 receive()는 attack 트랜잭션에서 실행되지만 VaultSecure 내부 withdraw의 외부 콜(external call) 프레임에서 처리되는 함수입니다. 현재 구조로는 withdraw 재진입이 막히면 revert가 상위 call (withdraw() 실패->receive() 실패 ... 첫 번째 withdraw 실패)까지 타고 올라와서 attack() 트랜잭션 자체가 롤백되는 구조 같습니다.
따라서 VaultSecureTest의 몇몇 테스트 함수에서 예상한 “첫 출금까지 유효” 상태가 만들어지지 않습니다. deposit()과 첫번째 withdraw까지는 유효하게 처리되는걸 전제로 attack()을 호출하는 test_ReentrancyAttack_AttackerGetsOnlyOwnDeposit(), test_ReentrancyAttack_CannotDrainVault() 두 개 테스트 함수 자체가 revert되며 성공 처리될 수 없어 보입니다.
CEI, ReentrancyGuard 모두 재진입하는 함수 호출을 revert 시키므로 현재 테스트를 성공시키기 위해선 receive()가 콜스택의 실패를 트랜잭션 전체에 전파하지 않고 프레임 단위로 흡수하도록 try-catch 구조로 돼야 하는게 아닌지 궁금합니다.
로컬 수정이 꼬여서 week-02의 커밋이 같이 올라왔습니다..
ReentrancyGuard 라이브러리 같이 푸시돼서 추적 제외했습니다..
포크한 디렉토리 최신화 완료
체크리스트
테스트
forge build성공forge test모든 테스트 통과제출 규칙
{username}/week-{XX}형식.env파일이 커밋에 포함되지 않음