본문 바로가기
Blockchain

[Blockchain] 가위바위보 스마트 컨트랙트 개선하기

by 개발자 염상진 2022. 7. 13.

가위바위보 스마트 컨트랙트 게임을 배포하고 난 후 문제점이 발견됩니다. 새로운 방을 생성한 방장이 입력한 조건값이 트랜잭션에 그대로 노출된다는 점입니다. 스마트 컨트랙트에서 발생한 트랜잭션을 뜯어보면 input Data 부분에 방장이 입력한 값이 버젓이 나오고 있습니다. 이에, 참여자들은 방장이 입력한 값을 보고 이길 수 있는 조건값을 걸어 무한정 이길 수 있게 됩니다.

 

이를 방지하기 위해서는 입력값을 외부에 노출되지 않도록 해야 합니다. 이 때 필요한 함수가 바로 해시 함수입니다.

 

 

 

 

 

 

[Blockchain] 가위 바위 보 스마트 컨트랙트 만들기

가위 바위 보 게임을 솔리디티로 작성할 수 있습니다. 플레이어들은 각각 가위, 바위, 보 3가지 옵션 중 하나를 선택해 게임에 참여할 수 있고, 승리한 플레이어는 베팅된 금액을 모두 가져갈 수

about-tech.tistory.com

 

 

입력값 숨기기

 

방장의 조건값을 외부에 노출하지 않으면서 가위바위보 게임 로직을 그대로 유지하기 위해서는 해시된 값을 입력하고, 게임의 결과를 판독할 때 복호화가 이뤄져야 합니다. 

createRoom과 joinRoom에서는 암호화된 해시값이 입력되고, compareHands나 payout() 함수에서는 복호화가 이뤄져야 합니다. 

 

① keccak256 해시 함수

솔리디티에서는 해시함수로 keccak256() 함수가 사용됩니다. bytes32형 데이터를 반환하며, 입력값으로는 abi.encodePacked()로 인자를 바이트 타입의 변수로 인코딩 한 값을 사용합니다. 

function keccak(uint256 _hand, string memory _key) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_hand,_key));
}

 

② verifyOriginator 함수

결과값을 확인하기 위해서 comparesHand()함수 내에서 verifyOriginator()함수를 사용합니다. 즉 가위바위보 입력값과 key값을 받아 해당 조건값을 입력한 참여자가 맞는지 해싱된 값을 사용합니다. 

function verifyOriginator(uint256 _hand, string memory _key, uint roomNum) private returns(bool) {
    require(msg.sender == rooms[roomNum].originator.addr);
    if(keccak(_hand, _key) == rooms[roomNum].originator.hashHand){
        rooms[roomNum].originator.hand = Hand(_hand);
        return true;
    }
    else { return false; }
}

 

 

 

③ 구조체 변경

참여자들은 가위바위보를 그대로 사용하는 것이 아니라 해시된 가위바위보 값을 가지게 됩니다. 

struct Player{
    address payable addr;
    uint256 playerBetAmount;
    Hand hand;
    // New code
    bytes32 hashHand;
    PlayerStatus playerStatus;
}

 

입력값 숨기는 방법

 

① 게임의 작동 순서는 먼저 참여자 혹은 방장은 내고자 하는 가위바위보를 해싱한 값을 keccak 함수를 통해 구하게 됩니다. 

 

 

② 해싱된 값을 가지고 방을 생성하고, 참여자들은 방에 참여해 베팅을 진행합니다.

 

해당 방의 잔액에는 1ETH가 들어있습니다.

 

트랜잭션을 확인해보면 방장이 입력한 값(가위를 냈습니다)이 해시값으로 암호화 되어 있어 확인할 수 없습니다. 해당 값을 확인하기 위해서는 해싱할 때 들어갔던 key값을 알아야 합니다. 

 

③ 새로운 참여자가 방에 참여합니다. 

 

④ compareHands() 함수로 결과를 확인하고 이더를 분배합니다.

 

추가 기능 구현하기

 

① 방에 참여자들 카운팅

방의 번호를 입력받아 해당 방에 참여한 플레이어의 수를 반환합니다. 블록체인에서 아무런 데이터도 변형하지 않으므로 view 함수로 작성합니다.

function checkNumOfPlayer(uint roomNum) public view returns(uint numOfPlayers){
    return rooms[roomNum].playerNum;
}

 

특정 방에 참여한 플레이어 수를 반환합니다.

 

 

 

② 가장 많은 베팅 금액 방 찾기

방의 정보를 담은 구조체형 변수 rooms을 참조합니다. 가장 많은 베팅 금액을 담고 있는 방을 찾기 위함이므로 인수는 받지 않으며 roomNum을 반환합니다. 

function checkMaxBetRoom() public view returns(uint8 MaxBetRoom){
    uint8 max = 0;
    uint8 maxBetRoom = 0;
    for(uint8 i=0; i<roomLen; i++){
        if(rooms[i].betAmount > max){
            max = uint8(rooms[i].betAmount);
            maxBetRoom = i;
        }
    }
    return maxBetRoom;
}

 

가장 많은 베팅 금액을 가진 방 번호를 반환합니다.

 

Reference

전체 소스코드 : Github

스마트 컨트랙트 : Etherscan (0x9d363fF4a841E596D0783D8106bf8B960Ee3F4f6)

 

 

 

[Blockchain] Remixd 사용하는 방법

Remixd란? 솔리디티 개발에 최적화된 IDE는 Remix입니다. 기본적으로 웹에서 작동하므로 브라우저의 캐시를 기반으로 작성한 코드를 저장하게 됩니다. 만약 브라우저 내 저장되어 있는 캐시 데이터

about-tech.tistory.com

 

 

[Blockchain] 작업증명(PoW) vs 지분증명(PoS) vs 위임지분증명(DPoS) 차이점

블록체인 네트워크에서 채굴을 하는 방식으로 여러가지 방식이 존재합니다. 어떤 블록이 유효한지 검증하고 새로운 블록을 생성하는 과정에서 누가 블록을 생성하고 검증할 권한을 가지냐가

about-tech.tistory.com

 

 

[Blockchain] 스마트 컨트랙트란?

블록체인 2.0인 이더리움이 주목받는 이유는 스마트 컨트랙트(Smart Contract) 덕분입니다. 스마트 컨트랙트는 블록체인 네트워크에 호스팅되어 실행되는 프로그램입니다. 미리 지정된 조건이 충족

about-tech.tistory.com

 

댓글