일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 러스트 기초 학습
- SBT표준
- 깃허브명령어
- 러스트 기초
- nestjs 튜토리얼
- ethers v6
- 스마트컨트렉트프록시
- ethers
- Vue
- 컨트렉트 배포 자동화
- rust 기초
- multicall
- chainlink 설명
- ambiguous function description
- vue기초
- 프록시배포구조
- 컨트렉트 동일한 함수이름 호출
- ethers type
- 러스트기초
- 체인의정석
- ethers websocket
- 머신러닝기초
- nest.js설명
- git rebase
- 스마트컨트렉트테스트
- ethers typescript
- 스마트컨트렉트 함수이름 중복 호출
- 스마트 컨트렉트 함수이름 중복
- 스마트컨트렉트 예약어 함수이름 중복
- Vue.js
- Today
- Total
체인의정석
Chain link 서비스 분석 - chain link VRF 분석 본문
이번 프로젝트의 장기적인 로드맵에 있어서 chain link를 연동하는 부분을 고려중이기 때문에 한번 살펴 보았다.
먼저 체인링크의 활용 방안은 스마트컨트렉트 내부에서 url에 대한 요청을 보내서 거기서 받은 응답값을 통해서 활용이 가능한 것이였다.
chain link VRF
랜덤 변수를 뽑아낼 때는 최근에 나온 체인링크 VRF를 활용하면 되었는데
https://docs.chain.link/docs/vrf/v2/best-practices/
일단 내부적으로는 랜덤 변수를 생성할 수 없기 때문에 외부에서 데이터를 가져와야 하는데
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
// Assuming only one random word was requested.
s_randomRange = (randomWords[0] % 50) + 1;
}
요런식으로 랜덤한 숫자 하나만 가져오게 되면 이걸 통해서 다양한 수치를 랜덤으로 뽑아낼 수 있다.
만약 동시에 여러개의 VRF 요청을 하려는 경우 아래와 같이 매핑을 사용해서 ID별로 여러개의 랜덤 변수를 담을 수 있도록 하는 응답값에 대한 Mapping과 해당 id를 요청한 주소를 매핑으로 저장시키는 mapping을 각각 추가 시켜서 요청시에 Id 별로 따로따로 요청을 하는 함수를 만들고 응답값은 복수로 받아올 수 있도록 아이디 별로 응답값을 저장시키는 식으로 구현할 수 있다.
mapping(uint256 => uint256[]) public s_requestIdToRandomWords;
mapping(uint256 => address) public s_requestIdToAddress;
uint256 public s_requestId;
function requestRandomWords() external onlyOwner returns (uint256) {
uint256 requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
s_requestIdToAddress[requestId] = msg.sender;
// Store the latest requestId for this example.
s_requestId = requestId;
// Return the requestId to the requester.
return requestId;
}
function fulfillRandomWords(
uint256 requestId,
uint256[] memory randomWords
) internal override {
// You can return the value to the requester,
// but this example simply stores it.
s_requestIdToRandomWords[requestId] = randomWords;
}
request를 트래킹하면서 아이디별로 인덱스를 따로 만들고 싶다면
mapping(uint256 => uint256) s_requestIdToRequestIndex;
mapping(uint256 => uint256[]) public s_requestIndexToRandomWords;
uint256 public requestCounter;
function requestRandomWords() external onlyOwner {
uint256 requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
s_requestIdToRequestIndex[requestId] = requestCounter;
requestCounter += 1;
}
function fulfillRandomWords(
uint256 requestId,
uint256[] memory randomWords
) internal override {
uint256 requestNumber = s_requestIdToRequestIndex[requestId];
s_requestIndexToRandomWords[requestNumber] = randomWords;
}
이런식으로 카운터 값을 주면서 주소값이 아닌 인덱스를 통한 관리도 가능하다.
마지막으로 예제에는 각각의 경로로 서로 다르게 랜덤 값을 관리하는 코드가 있엇는데
// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.
// It shows how to setup multiple execution paths for handling a response.
pragma solidity ^0.8.7;
import '@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol';
import '@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol';
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract VRFv2MultiplePaths is VRFConsumerBaseV2 {
VRFCoordinatorV2Interface COORDINATOR;
// Your subscription ID.
uint64 s_subscriptionId;
// Goerli coordinator. For other networks,
// see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations
address vrfCoordinator = 0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D;
// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations
bytes32 keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15 View in Tenderly ;
uint32 callbackGasLimit = 100_000;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;
// For this example, retrieve 1 random value in one request.
// Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
uint32 numWords = 1;
enum Variable {
A,
B,
C
}
uint256 public variableA;
uint256 public variableB;
uint256 public variableC;
mapping(uint256 => Variable) public requests;
// events
event FulfilledA(uint256 requestId, uint256 value);
event FulfilledB(uint256 requestId, uint256 value);
event FulfilledC(uint256 requestId, uint256 value);
constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) {
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
s_subscriptionId = subscriptionId;
}
function updateVariable(uint256 input) public {
uint256 requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
if (input % 2 == 0) {
requests[requestId] = Variable.A;
} else if (input % 3 == 0) {
requests[requestId] = Variable.B;
} else {
requests[requestId] = Variable.C;
}
}
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
Variable variable = requests[requestId];
if (variable == Variable.A) {
fulfillA(requestId, randomWords[0]);
} else if (variable == Variable.B) {
fulfillB(requestId, randomWords[0]);
} else if (variable == Variable.C) {
fulfillC(requestId, randomWords[0]);
}
}
function fulfillA(uint256 requestId, uint256 randomWord) private {
// execution path A
variableA = randomWord;
emit FulfilledA(requestId, randomWord);
}
function fulfillB(uint256 requestId, uint256 randomWord) private {
// execution path B
variableB = randomWord;
emit FulfilledB(requestId, randomWord);
}
function fulfillC(uint256 requestId, uint256 randomWord) private {
// execution path C
variableC = randomWord;
emit FulfilledC(requestId, randomWord);
}
}
결국
VRFCoordinatorV2Interface
해당 인터페이스를 통하여 체인링크의 스마트 컨트렉트에 접근을 하는 것이고 해당 컨트렉트에다가 트랜잭션을 직접 호출하면 응답값을 체인링크가 주는 형태이다. 위의 예시코드는 체인링크를 사용할 경우 해당 응답값을 받아와서 처리하는 체인링크의 고객인 개발자가 참고하고 구현할 코드이다.
지원 네트워크의 경우 evm 계열의 네트워크가 사용되는 것 같다.
https://docs.chain.link/docs/vrf/v2/supported-networks/
들어가면 이런식으로 해당 체인에서의 링크 토큰 주소 및 gwei key hash가 나온다. Key hash의 경우 주석을 살펴보니 사용할 최대 가스치인것 같다.
가장 많은 유저가 사용하는 것이 바로 requeset Random Wokrds 였는데
여기서 subId의 경우 구독 아이디로서 체인링크에서 돈을 내는 계정의 아이디라고 볼 수 있다. 따로 페이지에서 충전시켜 놓고 서비스를 구동하는 것을 이런식으로 스마트컨트렉트에서는 아이디만 받아와서 사용하는 구조를 취하고 있다.
그리고 응답값에 대한 gas limit도 걸어두고 받고 있는데 응답값이 큰 경우 가스비도 많이 발생하기 때문인것 같다. numWords같은 경우는 받을 랜덤 변수의 개수라고 볼 수 있다.
결국 서비스에서는 랜덤변수를 던져주고 여기에 대해 등록하거나 관리하는 부분을 컨트렉트가 해주게 된다.
'블록체인 > 퍼블릭 블록체인' 카테고리의 다른 글
컨트렉트 지갑 및 어셈블리어 참고 링크 (업데이트) (0) | 2022.09.15 |
---|---|
Chain link 서비스 분석 - 기본 아키텍쳐 (0) | 2022.09.13 |
블록체인 아키텍쳐) 블록체인에서의 Layer 구분 (0) | 2022.08.29 |
테스트 코드에서 이더리움을 전송하는 방법 (0) | 2022.08.13 |
faucet 리스트 (업데이트) (0) | 2022.04.27 |