API3의 QRNG란?

채동기·2023년 4월 12일
0

Oracle

목록 보기
8/14

API3의 QRNG(Quantum Random Number generator)에 대해서 알아보려고 합니다.

API3

API3 Foundation은 기존 써드 파티오라클 네트워크에서 더 많은 보안, 효율성 및 규정 준수 기능을 제공하는 퍼스트 파티 오라클 솔루션으로 전환하는 데 앞장서는 DAO(분산형 자율 조직)입니다. Airnode 퍼스트 파티 오라클을 통해 구동되는 API3의 분산형 API(dAPI)는 정량화 가능한 보안으로 분산 제어되고 블록체인 네이티브 데이터 피드입니다.

오라클이란?

블록체인에서는 블록체인 외부에 있는 데이터를 블록체인 상에서 사용할 수 있도록 하는 미들웨어를 의미합니다.

퍼스트파티 오라클

써드파티 오라클(ex:Chainlink)과 다르게 검증자 없이 데이터를 제공하는 오라클을 의미합니다.
써드 파티 오라클에서 데이터 제공자의 수익성 악화 문제를 해결하기 위해 탄생하였습니다.
퍼스트 파티 오라클은 데이터 제공자의 수익성이 향상되고 데이터제공 속도가 빠르다는 장점이 있지만, 데이터 제공이 중앙화되어 있기 떄문에 데이터 제공자가 악의적인 행동을 할 수 있다는 단점이 존재합니다.

QRNG(Quantum Random Number generator)

API3와 The Australian National University(ANU) Quantum Optics Group은 양자역학을 기반으로 한 난수를 무료로 제공합니다. 지불하는 것은 가스비 뿐입니다.

양자 역학을 이용하는 이유는 예측 불가능한 난수를 보장할 수 있고, 인간의 개입이 없이 자동으로 동작할 수 있기 때문입니다.

퍼스트 파티 오라클 시스템을 이용해서 직접 소비자에게 제공하기 떄문에 써드파티 오라클과 다르게 중간 과정에서의 공격에 취약하지 않습니다.

지원 체인

Arbitrum, Avalanche, BNB Chain, Ethereum, Fantom, Gnosis Chain, Metis, Milkomeda-Cardano, Moonbeam, Moonriver, Optimism, Polygon, and RSK.

사용법

qrng-example에서 ReadMe를 읽는 것을 권장합니다.

qrng-example/contracts/

  • QrngExamples.sol: QRNG 서비스를 호출하는 데 사용되는 샘플 requester

qrng-example/deploy/➚

  • deploy.js: requester를 체인에 배포하는 스크립트
  • setup.js: requester 계약에 매개 변수를 설정하는 스크립트입니다. 이 매개 변수는 QRNG 서비스를 호출할 때 사용
  • fund.js: requester가 가스 비용을 지불하는 데 사용하는 지갑에 자금을 공급하는 스크립트
QRNG 서비스를 사용하는 것은 무료이며, 구독 비용을 지불할 필요가 없습니다. 그러나 Airnode가 요청에 대한 응답으로 난수를 체인 상에 놓을 때 체인 상에서 가스 비용이 발생하며, 이 가스비에 대해서만 비용을 지불하면 됩니다.

QRNG 예제 프로젝트는 requester 주소를 사용하여 스폰서 지갑을 설정합니다. 그런 다음 Airnode가 요청에 응답할 때 가스 비용을 지불하는 데 이 지갑이 사용됩니다. 대안적인 방법으로는 Using QRNG - Remix Example 가이드에서처럼 Admin CLI를 사용하는 것입니다.

스폰서는 Airnode가 신뢰할 수 있는 것 이상으로 sponsorWallet에 자금을 공급해서는 안 됩니다. 왜냐하면 Airnode가 스폰서 지갑의 개인 키를 제어하기 때문입니다. 이러한 Airnode의 배포자는 관리 의무를 지지 않으며, sponsorWallet에 전달된 불필요한 자금의 손실 또는 오용 위험은 스폰서가 부담합니다.

인출

requester 컨트랙트에는 인출 또는 기타 추가 기능이 포함되어 있지 않습니다.

흥requester 컨트랙트에 인출 기능을 추가할 수 있습니다. 먼저, 자금을 sponsorWallet에서 sponsor로 이체해야 합니다. requester 컨트랙트가 sponsor로 설정되어 있으므로, requester 컨트랙트는 WithdrawalUtilsV0 컨트랙트에서 requestWithdrawal을 호출하여 인출 요청을 해야 합니다. AirnodeRrpV0 컨트랙트는 이 컨트랙트를 상속하므로, 게시된 주소를 사용할 수 있습니다. 두 번째로, requester 컨트랙트 소유자가 requester 컨트랙트 잔액을 자신의 주소로 이체할 수 있도록 requester 컨트랙트에 인출 함수를 추가해야 합니다.

예제

Remix IDE와 MetaMask를 사용할 것입니다. 그리고 이 툴에 대한 사전 지식이 있다는 가정하에 진행하겠습니다.

1. Coding the RemixQrngExample

Open in Remix

리믹스로 가면 RemixQrngExample에서 다섯개의 함수를 볼 수 있습니다. (setRequestParameters(), makeRequestUint256(), fulfillUint256(), makeRequestUint256Array(), fulfillUint256Array())

setRequestParameters()
온체인 상에 파라미터를 설정합니다.

 function setRequestParameters(
        address _airnode,
        bytes32 _endpointIdUint256,
        bytes32 _endpointIdUint256Array,
        address _sponsorWallet
    ) external {
        airnode = _airnode;
        endpointIdUint256 = _endpointIdUint256;
        endpointIdUint256Array = _endpointIdUint256Array;
        sponsorWallet = _sponsorWallet;
    }

makeRequestUint256()
makeRequestUint256() 함수는 AirnodeRrpV0.sol 프로토콜 컨트랙트의 airnodeRrp.makeFullRequest() 함수를 호출하여 요청을 저장하고 requestId를 발행합니다.

    function makeRequestUint256() external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256.selector,
            ""
        );
        waitingFulfillment[requestId] = true;
        latestRequest.requestId = requestId;
        latestRequest.randomNumber = 0;
        emit RequestedUint256(requestId);
    }

fulfillUint256()
대상이 되는 오프체인 QRNG Airnode는 요청을 수집하고 무작위 숫자와 함께 RemixQrngExample에 대한 콜백(callback)을 수행합니다.

    function fulfillUint256(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(
            waitingFulfillment[requestId],
            "Request ID not known"
        );
        waitingFulfillment[requestId] = false;
        uint256 qrngUint256 = abi.decode(data, (uint256));
        // Do what you want with `qrngUint256` here...
        latestRequest.randomNumber = qrngUint256;
        emit ReceivedUint256(requestId, qrngUint256);
    }

makeRequestUint256Array()
_endpointIdUint256Array를 인자로 받아 여러 개의 무작위 숫자를 요청할 수 있습니다.

    function makeRequestUint256Array(uint256 size) external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256Array,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256Array.selector,
            // Using Airnode ABI to encode the parameters
            abi.encode(bytes32("1u"), bytes32("size"), size)
        );
        expectingRequestWithIdToBeFulfilled[requestId] = true;
        emit RequestedUint256Array(requestId, size);
    }

fulfillUint256Array()
여러 개의 무작위 숫자가 요청되는 경우에 해당 요청의 콜백(callback)으로 작동합니다.

    function fulfillUint256Array(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(
            expectingRequestWithIdToBeFulfilled[requestId],
            "Request ID not known"
        );
        expectingRequestWithIdToBeFulfilled[requestId] = false;
        uint256[] memory qrngUint256Array = abi.decode(data, (uint256[]));
        // Do what you want with `qrngUint256Array` here...
        emit ReceivedUint256Array(requestId, qrngUint256Array);
    }

2. compiling the Contract

RemixQrngExample.sol 컨트랙트를 0.8.9버전으로 컴파일합니다.

3. Deploying the Contract

RemixQrngExample.sol 컨트랙트는 테스트넷에서만 사용해야합니다!!!!

  1. DEPLOY & RUN TRANSACTIONS 탭으로 이동 후 MetaMask를 사용하고 배포할 계정과 테스트넷으로 전환

  2. ENVIRONMENT 픽리스트를 선택하고 Injected Web3로 전환 후 Remix에서 선택한 테스트넷과 MetaMask에서 선택한 계정이 표시되는지 확인

  3. QrngReqester - contracts/QrngReqester.sol이 선택되어 있는지 확인

  4. _airnodeRrp 주소 매개 변수 값을 배포 버튼 옆의 필드에 추가합니다. 사용 중인 테스트넷의 주소 목록을 참조!!

  5. 배포를 클릭하고 MetaMask에서 트랜잭션을 승인

4. Setting the Parameters

요청을 하기 전에, 파라미터를 설정해야 합니다. 파라미터는 어떤 Airnode 엔드포인트가 호출될지를 결정하고, 응답을 받기 위해 가스 비용을 지불할 월렛을 정의합니다.

배포된 계약에서 Deployed Contracts 섹션을 펼치고, 해당 계약의 함수와 변수들을 노출합니다. 이름과 함께 표시된 계약의 주소를 확인하세요. 이는 나중에 필요한 요청자 계약의 주소입니다. 그다음, setRequestParameters 함수를 펼쳐보세요. 다음 내용을 함수에 해당하는 필드에 추가합니다.

_airnode: QRNG 서비스 제공자의 Airnode 주소입니다. nodary (0x6238772544f029ecaBfDED4300f13A3c4FE84E1D)를 사용하세요.

_endpointIdUint256: 단일 랜덤 숫자를 반환하는 nodary Airnode 엔드포인트 ID (0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78)입니다.

_endpointIdUint256Array: 랜덤 숫자 배열을 반환하는 nodary Airnode 엔드포인트 ID (0x27cc2713e7f968e4e86ed274a051a5c8aaee9cca66946f23af6f29ecea9704c3)입니다.

_sponsorWallet: nodary에서 사용하는 Airnode xpub와 RemixQrngExample.sol의 스마트 계약 주소, 그리고 해당 Airnode 주소를 이용해 파생된 월렛입니다. 이 월렛은 랜덤 숫자를 얻기 위해 가스 비용을 지불하는 데 사용됩니다. 파생 스폰서 월렛 주소를 Admin CLI의 derive-sponsor-wallet-address 명령으로 얻을 수 있습니다. 이 명령이 출력한 스폰서 월렛 주소를 사용하세요.

npx @api3/airnode-admin derive-sponsor-wallet-address \
  --airnode-address 0x6238772544f029ecaBfDED4300f13A3c4FE84E1D \
  --airnode-xpub xpub6CuDdF9zdWTRuGybJPuZUGnU4suZowMmgu15bjFZT2o6PUtk4Lo78KGJUGBobz3pPKRaN9sLxzj21CMe6StP3zUsd8tWEJPgZBesYBMY7Wo \
  --sponsor-address <use-the-address-of: RemixQrngExample.sol>

  # --airnode-address: Airnode address (nodary provider)
  # --airnode-xpub:    Airnode xpub (nodary provider)
  # --sponsor-address: Use the smart contract address for
  #                    RemixQrngExample.sol as displayed in the Remix IDE.

  # The command outputs.
  Sponsor wallet address: 0x6394...5906757
  # Use this address as the value for _sponsorWallet.

Remix의 Transact 버튼을 선택하여 스마트 컨트랙트에 매개변수를 보내세요. MetaMask에서 트랜잭션을 승인하세요. 트랜잭션이 완료되면, 매개변수 이름이 적힌 버튼을 클릭하여 각 매개변수의 값이 표시됩니다. 이러한 매개변수는 스마트 컨트랙트가 무작위 숫자를 요청할 때마다 사용됩니다.

5. Make a Request

마지막 단계에서 생성한 sponsor wallet을 충분히 펀딩했는지 확인하세요. 이 펀드는 Airnode가 콜백 함수 fulfillUint256()로 무작위 숫자를 반환할 때 가스 비용으로 사용됩니다.

마지막 단계에서 설정한 매개변수가 각 요청에 사용됩니다. 매개변수를 언제든지 변경할 수 있으며, 그 이후의 요청은 새로운 매개변수 세트를 사용합니다.

요청을 하려면 Remix에서 makeRequest 버튼을 선택하세요. MetaMask에서 트랜잭션을 승인하세요.

MetaMask에서 트랜잭션이 완료되면 Remix에서 lastRequest 버튼을 선택하세요. requestId와 randomNumber(0과 동일)이 표시됩니다. 이는 아직 무작위 숫자가 콜백 함수로 반환되지 않았기 때문입니다. requestId를 waitingFulfillment 필드에 복사하여 버튼을 선택하세요. 값이 true로 표시되면 콜백이 아직 수행되지 않았음을 의미합니다.

6. View the Response

오프 체인 Airnode가 요청을 수집하고, API 제공자를 호출합니다. API 제공자가 데이터를 반환하면 Airnode는 RemixQrngExample.sol 계약 함수 fulfillUint256(bytes32 requestId, bytes calldata data)로 다시 호출합니다.

다시 Remix에서 lastRequest 버튼을 선택하세요. 콜백이 성공적으로 완료되면 randomNumber가 표시됩니다. waitingFulfillment의 값은 false가 됩니다.

그래서 써? 말어?

chainlink의 VRF와 비교하기 위해 API3의 QRNG를 찾아보았다.
난수를 생성하는 과정부터 비용까지 너무 다르다.
물론 지원되는 체인을 사용해야 쓸 수 있는 서비스이긴 하다.
난수를 생성하기 위해 양자역학을 사용한다는 점이 체인링크의 VRF와 너무 달라서 재미있는 점 같다. 양자역학을 사용해서 난수를 얻기때문에 검증 가능한 랜덤성(VRF)이라고 할 수 없는 것 같다. 그리고 퍼스트 파티 오라클이기에 가능한 방법이라고도 생각된다. 무엇을 사용할 지를 고민 된다면 나의 프로덕트가 올라가 있는 체인을 지원하는 지를 확인해야 한다. 그리고 비용 측면과 검증 하는 과정이 필요한지 아니면 랜덤한 값만 있으면 되는지를 판단해서 사용하면 될 것 같다.
랜덤한 수를 생성한다는 것 외에는 비슷한듯 다른 서비스라고 생각되기 때문에 무엇이 좋고 안좋고를 따지기 보다는 필요에 맞는 서비스를 선택하면 될 것 같다.

출처

API3 백서
https://api3.org/QRNG
https://xangle.io/insight/research/62f5dd09c3202ff4a9d90953
https://medium.com/api3/api3-qrng-web3-quantum-random-numbers-4ca7517fc5bc
https://docs.api3.org/reference/qrng/
https://docs.api3.org/guides/qrng/
https://github.com/api3dao/qrng-example

profile
what doesn't kill you makes you stronger

0개의 댓글