Solidity Oraclize 튜토리얼

오라클 문제가 무엇인가?

  • 블록체인 안(온체인)에서 발생한 데이터가 아니라 블록체인 밖(오프체인)에서 발생한 데이터를 블록체인 안으로 가져올 때 신뢰성을 보장받을 수 없는데, 이러한 문제를 오라클 문제라고 합니다.

온체인, 오프체인 트랜잭션은 무엇인가?

  • 온 체인 트랜잭션(On-chain Transaction)
    말 그대로 체인 위에 발생하는 트랜잭션입니다. 그런데 여기에서의 체인은 메인(단일) 블록체인 네트워크를 의미합니다.
예 : 비트코인, 이더리움 등의 자체 네트워크를 구성하고 있는 블록체인 내에서 발생하여 블록에 기록되는 트랜잭션들입니다.
  • 오프 체인 트랜잭션(Off-chain Transaction)
    온 체인 트랜잭션의 정의를 이해하셨다면, 오프체인은 그냥 쉽게 이해 하실 수 있습니다. 그냥 메인 블록체인이 아닌 곳에서 발생하는 트랜잭션인 것입니다.
예 : 이더리움 네트워크의 입장에서는 비트코인 네트워크에서 주고 받는 트랜잭션은 오프체인 트랜잭션인 것입니다. 반대로 비트코인 네트워크의 입장에서는 이더리움 네트워크에서의 트랜잭션이 오프체인 트랜잭션이 되겠죠.

오라클라이즈는 무엇인가?

  • 오라클 문제를 해결하기 위한 하나의 방안으로 오프체인 — 온체인 사이에 위치하는 미들웨어입니다. 신뢰할 수 있는 third party 역할을 하여 신뢰성을 높이려 하고 있습니다. 탈중앙화 된 방법은 아닙니다.
  • Ethereum, Rootstock, R3 Corda, Hyperledger Fabric, EOS에서 오라클라이즈를 이용할 수 있습니다.

오라클라이즈는 어떻게 사용하는가?

데이터 소스 종류

  • URL: 웹사이트나 API를 호출한 값을 가져옵니다.
  • WolframAlpha: 울프럼알파 서비스에 검색한 결과 값을 가져옵니다.
  • IPFS: IPFS에 저장 된 파일에 접근합니다.
  • random: Ledger Nano S(하드웨어 지갑)에서 동작하는 안전한 어플리케이션으로부터 생성한 랜던한 바이트를 가져옵니다.
  • computation: 연산의 결과를 가져옵니다.
  • nested: 여러 종류의 데이터 소스 또는 같은 종류의 여러 데이터 소스에서 결과를 받아서 단일 결과를 가져옵니다.
  • identity: query 자체를 반환합니다.
  • decrypt: 오라클라이즈 개인키로 암호화 된 문자열을 복호화합니다.

파싱 가능한 데이터 형태

  • JSON
  • XML
  • HTML(XPATH)
  • Binary

가격

  • 컨트랙트 당 첫번째 call을 무료
  • 두번째 call 부터는 value에 ether를 넣어서 호출해야 됨

사용 방법

  • Solidity 코드 작성
pragma solidity ^0.4.25;
import "github.com/oraclize/ethereum-api/oraclizeAPI_0.4.25.sol";
contract Example is usingOraclize {
string public someValue;
event NewOraclizeQuery(string description);
event NewSomeValue(string value);
constructor() public {
update();
}
function __callback(bytes32 myid, string result) public {
(myid);
require (msg.sender == oraclize_cbAddress());
someValue = result;
emit NewSomeValue(someValue);
// do something with someValue
}
function update() public payable {
if (oraclize_getPrice("[데이터소스]") > address(this).balance) {
emit NewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
emit NewOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("[데이터소스]", "[URL, 검색어, 수식 등]");
}
}
}
  • 받은 데이터 사용
  1. Solidity 코드 내의 __callback 함수에서 처리
  2. Javascript의 watch로 NewSomeValue Log 발생까지 기다렸다가, 리턴되는 값을 가지고 처리
    - Using APIs in Your Ethereum Smart Contract with Oraclize

사용 예제

  • 유튜브 조회수 가져오기
예: 영상 만들 때 투자자들에게 수익 분배에 대한 부분을 코드로 작성, 주기적으로(또는 특정 날짜에 한번) update를 호출하여 수익 분배 조건에 따라 미리 설정해 놓은 계정으로 토큰(또는 이더)가 전송되도록 할 수 있다.
참고자료 : Youtube 광고 수익 정산 계약
pragma solidity ^0.4.25;
import "github.com/oraclize/ethereum-api/oraclizeAPI_0.4.25.sol";
contract YoutubeViews is usingOraclize {
string public viewsCount;
event NewOraclizeQuery(string description);
event NewYoutubeViewsCount(string views);
constructor() public {
update();
}
function __callback(bytes32 myid, string result) public {
(myid);
require(msg.sender == oraclize_cbAddress());
viewsCount = result;
emit NewYoutubeViewsCount(viewsCount);
// do something with viewsCount. like tipping the author if viewsCount > X?
}
function update() public payable {
if (oraclize_getPrice("URL") > address(this).balance) {
emit NewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
emit NewOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("URL", 'html(https://www.youtube.com/watch?v=9bZkp7q19f0).xpath(//*[contains(@class, "watch-view-count")]/text())');
}
}
}
  • 비행기 출발 시간 정보
예: 출발 예정 시간을 미리 입력해 놓고, 실제 출발한 시간을 나중에 입력해서 일정 시간 이상 연착이 된 경우 자동으로 보험금을 지급하는 항공기 연착 보험
참고자료
- AXA 보험사의 비행기 연착보험 Fizzy
- 프랑스 보험회사 AXA 이더리움을 이용한 비행기 연착 보험 출시
- Fizzy의 실제 컨트랙트
pragma solidity ^0.4.25;
import "github.com/oraclize/ethereum-api/oraclizeAPI_0.4.25.sol";
contract FlightInsurance is usingOraclize {
string public scheduledTakeoffTime;
string public actualTakeoffTime;
bool private isFirstCall;
event LogNewOraclizeQuery(string description);
event LogSetScheduledTime(string time);
event LogSetActualTime(string time);
constructor() public {
isFirstCall = true;
setScheduledTime();
}
function __callback(bytes32 myid, string result) public {
(myid); // for no warning
require(msg.sender == oraclize_cbAddress());
if(isFirstCall) {
scheduledTakeoffTime = result;
isFirstCall = false;
} else {
actualTakeoffTime = result;
// do something
}
}
function setScheduledTime() internal {
if (oraclize_getPrice("WolframAlpha") > address(this).balance) {
emit LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
emit LogNewOraclizeQuery("Oraclize query for flight scheduled time was sent, standing by for answer...");
oraclize_query("WolframAlpha", "United Airlines flight 895 departing on 2018-10-28 scheduled takeoff time");
}
}
function setActualTime() public payable {
if (oraclize_getPrice("WolframAlpha") > address(this).balance) {
emit LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
emit LogNewOraclizeQuery("Oraclize query for flight auctual time was sent, standing by for answer...");
oraclize_query("WolframAlpha", "United Airlines flight 895 departing on 2018-10-28 actual takeoff time");
}
}
}