블록체인 정보 맛보기 블록체인 [이더리움을 통해 맛보기] (4)
포스트
취소

블록체인 [이더리움을 통해 맛보기] (4)

좀 더 어려운 스마트 컨트랙 직접 만들어보기 (feat. Chainlink)

지난 포스트에서 스마트 컨트랙을 Solidity로 작성하는 방법을 배웠습니다.
그렇다면 이번엔 좀 더 구체적인 기능들이 있는 스마트 컨트랙을 작성하는 것을 해보도록 하겠습니다.

우선 앞으로 이 포스트 및 이외의 여러 스마트컨트랙 작성을 위해 꼭 필요한 배경지식을 잠깐 설명하겠습니다.

Solidity의 기능 추가 설명

난수

스마트컨트랙트에서 여러 서비스(게임, 추첨 등)를 제공하기 위해 난수가 필요한 경우들이 있습니다.
하지만 블록체인 상에서 난수를 발생시키는 것은 여러 위험성과 고려사항이 있습니다.

  • 난수를 생성하는 방법 2가지

    • keccak256 사용

      위 방법은 일반적으로 초심자들이 스마트컨트랙에서 난수를 발생시키기 위해 사용하는 방식입니다.
      다만 이 방식은 근본적으로 완전한 난수가 아니라 “의사 난수”이므로 외부에서 이를 예측하거나 조작하여 많은 피해가 발생한 사례들이 많습니다.

    • Chainlink VRF 솔루션 사용

      위의 keccak256을 이용한 난수에서 발생하는 문제들을 해결하기 위해 이더리움 Layer2 솔루션인 Chainlink를 이용하는 방법입니다.
      이는 탈중앙화된 클라이언트들을 통해 완전히 예측 불가능한 난수를 반환하는 솔루션을 제공합니다. 다만 이를 사용하기 위해선 Chainlink의 모듈을 Solidity 내에 포함해야하며 이 솔루션의 난수를 반환받는 함수를 호출하기 위해 LINK라는 토큰이 추가적으로 필요합니다.

난수의 생성엔 여러 방법들이 있겠으나 대표적인 두 방법을 확인해 보았습니다.
우리는 이제 난수를 생성하고 활용하는 함수를 포함한 스마트 컨트랙을 만들어서 솔리디티를 배워봅시다

근데 이렇게까지 억지로 기능을 넣어야만 했냐…?

기부금을 모으는 스마트컨트랙 만들어보기

요구사항 (토글)
  • FundRaising
    • 개발환경 : Remix IDE
    • 기능 설명
      • 일회성으로 동작하는 모금 컨트랙트
      • 일정기간 동안만 이더를 지불하여 모금에 참여할 수 있음
        1. 모금
        2. 현재 모금액 확인
        3. 모금액 수령 기능
        4. 랜덤한 기부자의 주소와 기부금을 반환 (의사 난수 사용)
        5. 난수 값 요청 (Chainlink VRF 사용)
        6. 난수 값 수신 시 이로 랜덤한 기부자의 주소와 기부금을 이벤트로 반환 (Chainlink VRF 사용)
    • 소스 파일 레이아웃
      • 파일 생성 (FundRaising.sol)
      • 라이선스 명시
      • version pragma 명시
      • import 선언 (체인링크 관련)
      • contract 선언
    • 생성자 선언
      • contract가 배포될 때 호출되는 특수 함수
      • 생성자 매개변수 추가 및 상태 변수에 저장
        • 체인링크 VRF를 사용하기 위한 기본 매개변수 추가
          • address vrfCoordinator, address link, bytes32 keyHash, uint256 fee 사용
          • VRFConsumerBase(vrfCoordinator, link) 활용
        • 컨트랙트 배포 시 모금 기간과 모금액 수령자를 지정하도록 변경
        • uint duration - 몇 초 동안 모금이 유효한지 의미 (3600 = 1시간)
        • 정수형 연산자 ‘+’
          • 현재 타임 스탬프 + duration을 fundRasingCloses의 값으로 지정
          • block.timestamp - 현재 블록의 유닉스 타임스탬프 값
    • 상태 변수 추가
      • 최소 모금액 지정
        • 기준 : 0.01ether
        • 이더리움 기본 단위 wei
          • 10^18wei = 1ether
          • 1e16==0.01 ether == 10**16
            • 단위 wei, ether등
            • ** : 지수 연산자
      • 종료 시점 지정
      • 모금 받을 주소 지정
      • Chainlink VRF를 사용하기 위한 s_keyHash 지정
      • Chainlink VRF를 사용하기 위해 사용할 가스량 지정
    • 필수 함수
      1. 모금 - fund
      2. 현재 모금액 - currentCollection
      3. 모금액 수령 - withdraw
      4. 랜덤한 기부자의 주소와 기부금을 반환 (의사 난수 사용) - selectRandomFunder
      5. 난수 값 요청 (Chainlink VRF 사용) - selectRandomFunder2
      6. 난수 값 수신 시 이로 랜덤한 기부자의 주소와 기부금을 이벤트로 반환 (Chainlink VRF 사용) - fulfillRandomness
    • fund()
      • 요구사항
        1. 0.01 ether 이상으로 모금에 참여할 수 있다.
          • 이더를 받을 수 있는 payable 함수
          • msg.value
            • 트랜잭션에 얼마를 보냈는 지 알 수 있는 전역 변수
          • 유효성 체크
            • 전송한 이더가 최소 금액 조건을 만족하는지 판별
        2. 지정된 모금 시간 이내에만 참여할 수 있다.
          • 조건문 if
          • 논리형 변수 : bool
          • 논리 연산자 : ==, !=, &&, | - 모금 유효 시간인지 판별 - 유효성 체크 함수
          • require(판별문, “에러 메시지”);
          • 판별문이 true가 아닌 경우 “에러 메시지” 출력 후 함수 바로 종료
          • if문을 사용하는 것 보다 require를 사용하는 것이 훨씬 경제적이다.
        3. 모금이 완료되면 모금자를 저장한다.
          • 주소형 address
          • 이더리움 주소를 저장할 수 있는 자료형
          • 초기값은 0x0 - msg.sender
          • 메시지 송신자를 알 수 있는 전역변수 - 자료형의 배열
          • uint[4] fixedArray;
          • uint[] dynamicArray;
          • push() : 배열의 가장 뒤에 요소 추가
    • currentCollection()
      • 요구사항
        1. 현재까지 모금된 금액을 누구나 확인할 수 있다.
          • 함수의 반환문 작성
          • address(this).balance;
          • return address(this).balance; - view
          • 상태 변수에 변화를 가하지 않고 읽기만 하는 함수
    • withdraw()
      • 요구사항
        1. 지정된 수령자만 호출할 수 있다.
          • 이더 전송이 일어나는 payable함수
          • 유효성 체크: 수령자가 맞는 지 확인
        2. 모금 종료 이후에만 호출할 수 있다.
          • 유효성 체크: 모금이 종료되었는 지 확인
        3. 수령자에게 컨트랙트가 보유한 이더를 송금한다.
          • 함수 modifier 작성
          • address의 멤버: balance, transfer
          • 컨트랙트가 보유한 이더
            • <address>.balance
          • 요청 주소에게 컨트랙트 보유 이더 송금
            • <address payable>.transfer(uint256 amount)
    • selectRandomFunder
      • 요구사항
        1. keccak256를 활용하여 난수를 생성한다.
          • 가스가 덜 생기도록 view로 작성
          • 해당 함수가 안전한지 확인
        2. 모금자 배열 내에서 랜덤으로 모금자 주소와 해당 주소의 기부금 액수를 반환한다.
        3. 누구든지 요청 가능
    • selectRandomFunder2
      • 요구사항
        1. Chainlink VRF를 활용하여 Chainlink에 난수 값을 요청한다.
        2. 스마트컨트랙의 생성자만 호출할 수 있다.
          • 유효성 체크: 스마트 컨트랙 생성자가 맞는 지 확인
        3. 스마트컨트랙이 가진 Link 토큰이 충분해야 호출할 수 있다.
          • 유효성 체크: 가스로 필요한 Link 토큰의 양이 충분한지 확인한다.
    • fulfillRandomness
      • 요구사항
        1. Chainlink VRF에서 난수값을 수신했을 때 동작한다.
        2. 모금자 배열 내에서 랜덤으로 모금자 주소와 해당 주소의 기부금 액수를 반환한다.
        3. 스마트컨트랙 내부에서만 호출 가능

Solidity 코드 (from Gist)

리믹스로 위 코드 테스트 해보기

체인링크 VRF(selectRandomFunder2)실행 결과

Untitled.png

스마트 컨트랙의 이벤트로 결과를 확인할 수 있다.



이번 포스트에선 Solidity로 구체적인 기능을 가진 스마트 컨트랙을 작성해보았습니다.
내용이 조금 어려울 수 있으나 코드와 주석을 잘 보시면 좀 더 심화적인 학습이 가능하리라 생각합니다.

감사합니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

블록체인 [이더리움을 통해 맛보기] (3)

좋은 개발자가 되기 위한 방법론