블록체인 분야에서 오라클은 체인의 스마트 계약에 외부 정보를 제공할 수 있는 시스템입니다. 스마트 계약과 블록체인 외부 세계를 연결하는 미들웨어로서 오라클은 블록체인에서 스마트 계약을 위한 데이터를 제공하는 매우 중요한 인프라 역할을 수행합니다.
예를 들어, 이더리움 네트워크에서 스마트 계약을 생성하면 이 계약은 특정 날짜의 원유 거래량 데이터에 액세스해야 합니다. 하지만 스마트 계약 자체로는 이러한 오프체인 실제 데이터를 얻을 수 없으므로 오라클을 통해 구현되어야 합니다. 이 경우 스마트 계약은 필요한 날짜의 원유 거래량을 이벤트 로그에 기록합니다. 그런 다음 거래 요청이 수신되면 이 이벤트 로그를 모니터링하고 구독하는 프로세스가 오프체인에서 시작됩니다. 온체인 거래를 제출하고 계약의 관련 메서드를 호출하면 지정된 날짜의 원유 거래량 정보가 스마트 계약에 업로드됩니다.
데이터 출처: https://defillama.com/oracles
체인링크
블록체인에서는 Chainlink 오라클이 가장 큰 시장 점유율을 차지하고 있습니다. Chainlink는 현실 세계에서 생성된 데이터를 가장 안전한 방식으로 블록체인에 제공하는 역할을 하는 분산형 오라클 프로젝트입니다. 체인링크는 오라클 기본 원칙의 구현을 바탕으로 경제적 인센티브를 통해 LINK 토큰을 중심으로 한 선순환 생태계를 구축했습니다. 체인링크 오라클은 LINK 토큰 전송을 통해 실행되어야 합니다. LINK는 이더리움 네트워크의 ERC677 계약입니다. LINK ERC677 토큰을 기반으로 한 oracle 기능은 요청/응답 모드에 속합니다.
ERC677 토큰의 transferAndCall
오라클은 본질적으로 서비스를 제공하는 당사자입니다. 체인링크가 오라클 프레임워크를 설계할 때 가장 먼저 떠오른 것은 오라클 사용자가 서비스를 제공한 오라클에 서비스 수수료를 지불하는 방법이었습니다. 그러나 표준 동종 토큰 계약 ERC20은 결제 후 서비스 제공 요구를 충족할 수 없기 때문에 ChainLink 자체는 Oracle 서비스 시나리오에 적합한 표준인 ERC677을 제안했습니다.
위 코드에서 볼 수 있듯이 ERC677은 실제로 표준 ERC20을 기반으로 transferAndCall 메소드를 추가합니다. 이 방법은 결제와 서비스 요청을 하나로 결합하여 Oracle 비즈니스 시나리오의 요구 사항을 충족합니다.
사용자가 전송을 위해 transferAndCall을 수행할 때 ERC20 전송 외에도 to 주소가 계약 주소인지 여부도 판단합니다. 그렇다면 to 주소의 onTokenTransfer 메소드가 호출됩니다. (ERC677Receiver에는 onTokenTransfer라는 하나의 메소드만 있습니다)
Etherscan으로 이동하여 LINK 토큰의 계약 소스 코드를 볼 수도 있습니다: https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca#code
LINK 토큰이 구현되면 여러 쌍의 _to 주소를 확인하는 것 외에도 실제로 ERC677의 transferAndCall 메서드를 상속한다는 것을 알 수 있습니다. 참고: oracle 서비스를 요청하기 전에 oracle이 소비자에게 서비스를 제공하려면 먼저 비용을 지불해야 하기 때문에 oracle을 신뢰할 수 있는지 여부를 먼저 확인해야 합니다. (누구나 오라클 서비스를 제공할 수 있습니다)
오라클 신뢰성 분류
온체인 오라클 요청
오라클 컨트랙트의 onTokenTransfer 메소드가 어떻게 구현되는지 살펴보겠습니다.
오라클의 소비자가 transferAndCall 메소드를 사용하여 오라클의 서비스에 대한 비용을 지불하고 요청할 때 여기의 주소는 요청된 오라클의 주소입니다. oracle 시스템의 onTokenTransfer 메소드는 먼저 전송이 LINK 토큰(LINK만)인지 확인합니다. 이는 실제로 msg.sender가 Link 토큰 계약의 주소인지 여부를 결정합니다. 그런 다음 _data의 길이가 최대 제한을 초과하는지 여부를 판단합니다. 마지막으로 _data에 "oracleRequest"로 시작하는 함수 선택기가 있는지 판단합니다. 물론 여기서의 기능 선택기는 오라클 머신이 제공하는 서비스에 따라 커스터마이즈될 수 있으며, 반드시 "oracleRequest"일 필요는 없습니다. 이는 오라클 머신이 외부 세계에 어떤 종류의 인터페이스를 노출하는지에 따라 달라집니다.
이러한 수정자가 전달되면 현재 함수 호출자와 전송 금액이 _data의 내용과 동일한지 확인합니다. 이러한 일련의 보안 검사를 통과한 후 현재 Oracle 계약은 위임자 호출을 통해 호출됩니다. 물론 _data에 있는 function selector를 확인하였기 때문에 실제로 oracleRequest 메소드를 호출하게 된다.
먼저 oracle 요청자와 그가 보낸 nonce를 연결한 다음 이를 이 요청의 requestId로 해시하고 커밋 매핑을 확인하여 고유 ID인지 확인합니다. 확인 후 문제가 없으면 만료 시간을 설정하고, 커밋에 requestId를 추가하고, _결제, _callbackAddress, _callbackFunctionId, 만료를 값으로 연결합니다. 가장 중요한 것은 CBOR(Concise Binary Object Representation) 데이터인 요청 data_data가 포함된 OracleRequest 이벤트를 발행하는 것입니다. 인코딩 형식은 가볍고 간결하며 간단히 바이너리 형태의 JSON 형식으로 이해하면 됩니다. 이 데이터는 오프체인 노드가 어떻게 설계되었는지에 따라 다양한 형태가 될 수 있습니다.
예: 체인링크: ETH/USD Aggregator, 트랜잭션에는 OracleRequest 이벤트가 포함됩니다.
OracleRequest 이벤트 예
이 이벤트는 ETH/USD 가격 집계자 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F가 oracle: 0x7e94a8a23687d8c7058ba5625db2ce358bcbd244로 보낸 가격 데이터 요청임을 알 수 있습니다. oracle이 요청 데이터를 반환하면 반환된 계약 주소: 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F, 호출해야 하는 메서드 ID: 6A9705B4 및 만료 시간: 1618185924를 알 수 있습니다.
오프체인 노드 응답
3.1 오프체인에서 fillOracleRequest 호출
첫 번째 확인:
- onlyAuthorizedNode: 함수 호출자(msg.sender)는 계약의 소유자이거나 승인된 목록에 있어야 합니다.
- isValidRequest: 계속해서 약정 매핑으로 이동하여 requestId가 존재하는지 확인합니다.
- 결제, callbackAddress, _callbackFunctionId 및 만료를 연결하여 약정 맵의 requestId에 해당하는 값인지 확인합니다.
이러한 검사가 통과되면 이 요청 비용이 인출 가능한 토큰에 누적되어 인출 가능한 금액을 기록합니다. 그러면 _requestId가 약속 맵에서 제거됩니다. 마지막으로 남은 가스량을 계산하여 요청을 발행한 컨트랙트의 콜백 함수를 실행하는 데 필요한 최소 가스량인 MINIMUM_CONSUMER_GAS_LIMIT보다 큰지 확인합니다.
위의 확인 사항이 통과되면 요청자 계약의 콜백 함수를 정식으로 호출 형식으로 호출할 수 있습니다.
요청에 대한 응답은 최대한 빨라야 하므로 ZAN의 노드 서비스( https://zan.top/home/node-service?chInfo=ch_WZ )를 사용하여 응답 속도를 향상시키는 것이 좋습니다. 노드 서비스 콘솔에서 해당 RPC 링크를 찾아 체인 외부로 트랜잭션을 보내는 속도를 높일 수 있습니다.
3.2 콜백 함수
이전에 우리는 oracleRequest를 통해 콜백 함수의 ID가 6A9705B4라는 것을 알았고 쿼리를 통해 해당 메서드가 "chainlinkCallback(bytes32,int256")임을 발견했습니다.
verifyChainlinkCallback은 사용자 정의 가능한 함수입니다. 수정자는 다음과 같습니다.
PendingRequests에서 요청한 Oracle에 해당하는 _requestId가 일치하는지 확인합니다. 그리고 ChainlinkFulfilled 이벤트를 내보냅니다.
확인이 통과되면 응답이 추가로 처리될 수 있습니다. 여기에서 답변 매핑이 업데이트됩니다. 그런 다음 가격 오라클인 경우 응답 가격 데이터가 currentPrice에 할당되어 해당 가격 업데이트를 수행합니다.
이상이 보편적인 오라클 서비스의 전체 과정입니다.
가격 오라클 요청 및 응답 프로세스에 대해 간략하게 설명하기 위해 Chainlink에서 제공하는 "TestnetConsumer" 계약의 "requestEthereumPrice" 메소드를 예로 들어 보겠습니다. 이 함수는 다음과 같이 정의됩니다.
구현되는 기능은 지정된 API(cryptocompare)에서 ETH/USD의 거래 가격을 얻는 것입니다. 함수에 의해 전달된 매개변수는 지정된 oracle 주소와 jobId입니다. 일련의 요청 매개변수를 조합한 후 "sendChainlinkRequestTo" 메소드를 호출하여 요청을 보냅니다. " sendChainlinkRequestTo "는 Chainlink에서 제공하는 라이브러리에 정의된 인터페이스 메소드로 다음과 같이 정의됩니다.
전송을 수신한 후 Oracle 계약은 "onTokenTransfer" 메소드를 트리거하여 전송의 유효성을 확인하고 "OracleRequest" 이벤트를 발행하여 보다 자세한 데이터 정보를 기록합니다.
이 로그는 oracle 계약의 로그에서 찾을 수 있습니다. 체인 아래의 노드는 해당 토픽의 로그를 구독하게 되며, 기록된 로그 정보를 얻은 후 요청의 특정 정보를 구문 분석하고 네트워크 API 호출을 통해 요청 결과를 얻습니다. 그런 다음 트랜잭션을 제출하면 Oracle 계약의 "fulfillOracleRequest" 메소드가 호출되어 데이터를 체인에 제출합니다.
이 메서드는 일련의 테스트를 수행하고 이전에 기록된 콜백 주소와 콜백 함수를 통해 결과를 소비자 계약에 반환합니다.
그래서 개발자로서 이러한 URL을 직접 지정하지 않고 기존 통화 쌍 가격을 사용하고 싶습니다. 그렇게 할 수 있습니까?
대답은 '예'입니다. 이를 사용하는 첫 번째 방법, 공식 샘플 코드는 다음과 같습니다.
우선, 각 거래 쌍에는 다음과 같이 실제로 AggregatorProxy인 Aggregator라고도 불리는 별도의 가격 피드가 있습니다.
이 인터페이스의 구체적인 구현은 비교적 간단합니다. https://etherscan.io/address/0x6Df09E975c830ECae5bd4eD9d90f3A95a4f88012#code를 참조하세요.
총 5가지 쿼리 방법이 있습니다.
- 소수(): 반환된 가격 데이터의 정밀도 자릿수, 일반적으로 8 또는 18
- 설명(): 일반적으로 ETH/USD와 같은 거래 쌍의 이름입니다.
- version(): 주로 Proxy가 가리키는 Aggregator 유형을 식별하는 데 사용됩니다.
- getRoundData(_roundId): 라운드 ID를 기반으로 현재 가격 데이터를 가져옵니다.
- 최신RoundData(): 최신 가격 데이터를 가져옵니다.
대부분의 애플리케이션 시나리오에서 계약은 최신 가격만 읽어야 합니다. 즉, 마지막 메서드를 호출하고 해당 반환 매개변수에서 응답은 최신 가격입니다.
또한 대부분의 애플리케이션은 가격 책정 단위로 USD 단위 의 토큰 가격을 읽습니다. 그렇다면 가격 책정 단위인 USD 단위의 정확한 숫자는 균일하게 8자리이므로 일반적인 상황에서는 거래할 필요가 없습니다. 다양한 토큰을 기반으로 하는 다양한 정밀도 문제가 있습니다.