[Ethereum] 랜덤 NFT 만들기

0xDave·2022년 8월 31일
0

Ethereum

목록 보기
8/112
post-thumbnail

🤷‍♂️ 난수 생성의 어려움


이더리움에서는 랜덤함수를 제공하지 않는다. 생성되는 블록의 번호나 해시값으로 난수를 생성하면 채굴자는 자신에게 유리한 블록만 채굴하는 경우가 발생할 수 있다. 또한 Don't trust, just verify 라는 말이 있듯이 블록체인에서는 정해진 상태 값과 인풋 값이 있을 때 그 결과값 또한 예측한 그대로 똑같은 값만 내뱉어야 한다. 난수 생성은 이와 정반대의 특성을 갖고 있기 때문에 블록체인에서 난수를 만든다는 것은 쉬운 일이 아니다.


⚡️ 해결방안


1. 체인링크 VRF

체인링크에서는 온체인에서 검증 가능한 난수를 무작위로 생성할 수 있는 기능인 VRF(Verifiable Random Function)을 제공한다. 컨트랙트에서 VRF Coordinator로 난수 생성을 요청하면(온체인으로 동작) VRF CoordinatorVRF Node로 요청을 전달한다. VRF Nodeblockhashnonce 값을 이용해 난수를 생성(오프체인으로 동작)하고 다시 VRF Coordinator로 결과를 보낸다. 마지막으로 결과값을 받은 VRF Coordinator는 생성된 난수를 검증하는 절차를 거친다. 사용자는 VRF를 구독하고 미리 LINK토큰을 입금해놓아야 하며, LINK토큰을 비용으로 지불해야 한다는 단점이 있다.

2. keccak256

예제에서 사용한 keccak256은 암호화 해시 알고리즘이다. 입력값이 한 글자만 바뀌어도 결과가 완전히 달라진다. 사용자가 많은 Dapp의 경우 악의적인 노드가 자신에게 유리한 방향으로 악용할 수 있다는 단점이 있다. 하지만 예제처럼 작은 Dapp의 경우 그럴 일이 없으니 마음 놓고 사용한 것 같다.

abi.encodePacked

keccak256을 사용할 때는 주로 abi.encodePacked를 통해 bytes 값을 얻어서 인자로 넣어준다. 예전에는 keccak256 함수도 여러 인자를 받을 수 있었다. 하지만 현재는 여러 개의 인자를 넣어주려면 인코딩 해서 넣어줘야 한다. 인코딩 할 때는 여러 방법이 있지만 여기선 abi.encodePacked를 사용했다.

인코딩의 한 종류인 abi.encode는 length 값을 포함해서 각 인자당 32bytes로 고정된 결과값을 리턴하기 때문에 복잡해보이는 반면, abi.encodePacked는 전달받은 인자를 length 정보를 제외하고 인코딩해주기 때문에 조금 더 간결한 결과값을 얻을 수 있다.

FIRST_WORD와 string으로 만든 tokenId를 인자로 넣어줬다. 굳이 FIRST_WORD를 하드코딩해서 넣어 줄 필요는 없지만 예제에서는 램덤 소스로 사용했다. 이후 배열의 길이에 맞게 나눈 나머지를 구하고 이를 배열 index 값으로 활용했다. 나머지 값을 index로 사용하면 배열의 길이를 초과한 숫자가 나오지 않기 때문.


출처 및 참고자료


  1. 랜덤
  2. Introduction to Chainlink VRF
  3. Random Number Generator in Solidity using keccak256
  4. What are ABI encoding functions in Solidity 0.4.24?
profile
Just BUIDL :)

0개의 댓글