- 지금까지는 아래 그림과 같이 자바스크립트 코드에서 ABI(application binary interface)를 참조하게 만들어 주었다.
이제부터는 ①번에 해당하는 솔리디티 구현을 해 볼 것이다.
- 동전 던지기 게임을 구현할 것인데 아래 그림은 컨트랙트의 주요 로직이다.
- 솔리디티에는 계정주소를 담는 address라는 타입이 있다.또한 솔리디티에서는 금액(value)의 단위를 설정하지 않으면
최소단위인 wei로 간주한다. 아래는 관련 코드이다.
cf) 1 wei = 1 x 10^(-18) ETH
address owner; // 계정 주소를 담을 수 있는 타입
// 생성자
constructor() public {
owner = msg.sender; // 컨트랙트 관리를 위해 컨트랙트 소유자를 기록
}
msg.sender; // 메소드 호출자의 계정 주소
msg.value; // 메소드 호출자가 보낸 송금액(wei)
block.number; // 트랜잭션이 담긴 블록 번호
address(this).balance; // 컨트랙트가 가진 잔액(wei) cf) 1 wei = 1 x 10^(-18) ETH
address player;
player.send(10 ether); // 플레이어에게 10이더 전송
player.transfer(10 ether);
- 베팅 정보를 저장하기 위한 구조체이다.
mask는 uint8 타입의 변수로 0000 0010이 앞(Head), 0000 0001이 뒤(Tail)를 의미한다.
numberOfBetBit는 플레이어가 동전의 양 면에 베팅하는 것을 막기 위해서 1의 갯수를 검사하기 위해 있는 코드이다.
예를들어 0000 0011인 경우 1의 갯수가 2이므로 플레이어가 양면에 베팅을 하는 경우이다.
동전 던지기 게임에서는 플레이어가 한 면에만 베팅을 해야 하므로 0000 0001이 나와야 한다.
// 베팅 정보를 저장하기 위한 구조체
struct Bet {
uint amount; // 베팅금액(wei)
uint8 numberOfBetBit; // 플레이어가 선택한 면의 개수
uint placeBlockNumber; // 플레이어가 베팅한 거래 정보가 담긴 블록 번호
uint8 mask; // 플레이어가 선택한 동전 면
address gambler; // 플레이어의 계정주소
}
- 이렇게 베팅 구조체를 정의하고 나면 어떤 플레이어의 정보인지 기록을 해야한다. 이때 사용하는 데이터 타입이
mapping이다. 이때 Bet은 컬럼명이 아니라 타입임을 유의해야 한다.
예를 들어 어떤 계정 주소에 베팅한 금액을 알려면 bets[주소].amount를 사용하면 된다.
mapping(address => Bet) bets; // 테이블과 유사하지만 컬럼명이 없는 맵
- modifer는 특정함수를 오너만 이용할 수 있게 바꿀 수 있다. 함수 뒤에 onlyOwner 적용을 하면 해당 함수가
실행 될 때 onlyOwner에서 msg.sender와 오너가 같은지를 체크한다.
- selfdestruct는 컨트랙트 비활성화 시킬 수 있는 솔리디티 내부 함수이다. 한 번 비활성화 하면 다시 되돌릴 수는 없다.
selfdestruct를 수행하면 함수 내에 적힌 주소(owner)로 잔액을 이동시키고 비활성화가 된다.
해당 함수는 아무나 수행해서는 안 되므로 주로 modifer와 함께 사용된다.
- 솔리디티에서는 기본적으로 함수가 리턴된다고 해서 그 결과값이 화면으로 리턴되지는 않는다.
이벤트 함수는 어떤 메소드 실행 후에 그 결과를 화면으로 리턴하고 싶을 때 사용한다.
- Fallback 함수는 이름없는 함수로 파라미터, 리턴 값을 가질 수 없다. 컨트랙트에 하나만 존재할 수 있다.
주로 이더리움을 받기 위해서 사용한다.
- 상금 계산은 아래와 같이 진행된다.
o 블록해쉬
- 블록 해쉬란 블록체인을 이루고있는 블록들의 식별번호(id)이다. 이 값은 유일하고 중복되지 않는다.
채굴자들이 이더마인 등의 프로그램을 돌리는 것도 이 블록 해쉬 값을 찾기 위해서이다.
이 값을 찾아야만 블록체인에 블록을 추가할 수 있고, 그 보상으로 코인을 주는 것이다.
- 솔리디티에는 난수를 생성하는 함수가 없다. 때문에 난수를 쉽게 생성하기 위해서 블록 해쉬를 사용한다.
우선 어플리케이션 화면에서 난수하나를 주어서 난수번째 블록을 선택하여 블록 해쉬값을 정한다.
플레이어는 블록 해쉬값을 모르고 운영자는 어플리케이션 화면에서 생성되는 난수를 모르므로 공정하다고 볼 수 있다.
이것도 특정 난수에 의해 결과값이 반복될 수 있으므로 위에서 정의한 구조체의 placeBlockNumber값을 이용한다.
이는 발생하는 트랜잭션의 블록번호이다. 이 두 가지 값을 abi.encodePacked(concat과 비슷)로 결합해서
16진수 문자열을 만들고 이를 해쉬함수로 해쉬한다. 결국 최종값은 32바이트가 되고 이를 uint로 형변환하여 사용한다.
- 예를들어 reveal이 0이 나왔다면 반환값은 2^0, 즉 1이다. 만약 플레이어가 뒷면에 베팅했다면
Bet와 1을 AND연산 한 값이 1(true)가 나오게 되고 상금을 받아가는 것이다.
- 참고로 솔리디티에서는 난수를 생성할 때 블록해쉬로 생성하는 것을 권하지 않는다고 한다.
이는 마이닝에 의해 값이 정해지기 때문인데 채굴자들이 블록해쉬 값을 조작할 가능성도 있기 때문이다.
그래서 신뢰할 수 있는 외부 기관으로부터 난수를 전달받는 것을 추천한다고 한다(ex Oraclize).
하지만 필자는 공부를 위한 소규모 프로젝트이므로 신경쓰지 않아도 될 것 같다.
'Block Chain Development' 카테고리의 다른 글
이더리움 기반 Dapp 개발 연습 #8 (단위테스트2) (0) | 2022.02.09 |
---|---|
이더리움 기반 Dapp 개발 연습 #7 (코드) (0) | 2022.02.07 |
이더리움 기반 Dapp 개발 연습 #5 (Truffle React Unboxing) (0) | 2022.01.31 |
이더리움 기반 Dapp 개발 연습 #4 (단위 테스트) (0) | 2022.01.27 |
이더리움 기반 Dapp 개발 연습 #3 (배포) (0) | 2022.01.25 |