[#9 Crypto Zombies] Oracle 빌드하기

cat_dev·2021년 3월 7일
0

Solidity

목록 보기
9/9
post-thumbnail

Oracle이란?

Oracle을 사용하는 이유

블록체인에서 데이터를 바로 끌어오는 것이 보안상 불가능하기때문에 오라클을 이용해 데이터를 끌어온다.

Oracle 통신 방식

Oracle 사용 구조 만들기

├── caller
│   ├── contracts
│   ├── migrations
│   ├── test
│   └── truffle-config.js
├── oracle
│   ├── contracts
│   ├── migrations
│   ├── test
│   └── truffle-config.js
└── package.json

오라클 통신

오라클 컨트랙트 부르기

caller 컨트랙트가 오라클과 통신하기 위해서는 인터페이스를 정의해야 한다.

인터페이스가 필요한 이유

  • 인터페이스는 함수 선언만 한다
  • 오라클과 통신하기 위해 반드시 정의 필요

call 하기

  1. FastFood라는 contract가 있다고 가정
pragma solidity 0.5.0;

contract FastFood {
  function makeSandwich(string calldata _fillingA, string calldata _fillingB) external {
    //Make the sandwich
  }
}
  1. FastFood contract 부르는 PrepareLunch contract 만들고 인터페이스 정의하기
pragma solidity 0.5.0;
//인터페이스 정의하기
//FastFood안에 있는 makeSandwich라는 함수가 컨트랙트를 부른다
interface FastFoodInterface {
   function makeSandwich(string calldata _fillingA, string calldata _fillingB) external;
}
  1. 인터페이스를 인스턴스화하고 함수를 call 한다.
pragma solidity 0.5.0;
import "./FastFoodInterface.sol";

contract PrepareLunch {

  FastFoodInterface private fastFoodInstance;

  function instantiateFastFoodContract (address _address) public {
    fastFoodInstance = FastFoodInterface(_address);
    fastFoodInstance.makeSandwich("sliced ham", "pickled veggies");
  }
}

Mapping을 req 기록으로 사용하기

이더 가격 업데이트 하기

  • 오라클에서 이더리움 가격 끌어오려면 getLatestEthPrice() 를 작동시켜야 한다.
  • 하지만 이 작업이 비동기적으로 일어나서 이건 유니크한 id만 리턴한다.
  • 대신에 callback함수가 이더 가격을 업데이트해준다.

map으로 callback 검사하기

//맵핑 정의
mapping(address => uint) public balances;
//msg.sender == address
balances[msg.sender] = someNewValue
  • uint 값은 맨 처음에 0 으로 초기화된다.
  • 새로 받은 값을 이렇게 맵으로 저장!

callback 함수의 역할

callback 함수 작동 순서

  1. 함수가 인증된 id 로 부터 호출되었는지 require써서 검사
  2. 인증된 id일 경우 myRequests 맵핑에서 제거
  3. 프론트엔드에게 이더 가격이 변동되었다고 알림 날림

오라클 인증

인증된 주소인지 검사하기

  • 오라클의 주소를 담은 변수를 이용해서 확인한다.
  • 함수를 부른 곳의 주소가 이 오라클 주소인지를 확인하면 된다.
  • 솔리디티의 msg.sender 를 이용해서 검사한다.
    modifier onlyOracle() {
      require(msg.sender==oracleAddress, "You are not authorized to call this function.");
      _;
    }
  • 뒤의 구문은 만약 아닐 경우 나는 오류 메세지

오라클 컨트랙트

오라클 컨트랙트의 목적

  • caller contract가 이더 가격 피드에 접근할 수 있게 해주는 다리같은 역할을 한다.
  • getLatestEthPrice()setLatestEthPrice() 두 개를 implement 해서 사용한다.

getLatestEthPrice()

  • 오라클은 맨 처음 request id 를 계산한다.
  • request id 는 보안상의 이유로 계산하기 힘들게 만들어야 한다.
uint randNonce = 0;
uint modulus = 1000;
uint randomNumber = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % modulus;
  • 위 코드처럼 keccak256으로 랜덤 넘버를 생성한다.
function getLatestEthPrice() public returns (uint256) {
    randNonce++;
    uint id = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % modulus;
  //리퀘스트 트래킹
    pendingRequests[id] = true;
  //이벤트가 발생했음을 알려줌
    emit GetLatestEthPriceEvent(msg.sender, id);
  //id 리턴
    return id;
  }
  • 리퀘스트 트래킹하는 시스템을 매핑으로 만들 수 있다.
  • 마지막에 이벤트가 발생했음을 알려줘야 함
  • request idreturn해야 함

setLatestEthPrice()

함수 설명

  • 위에서 이더 가격을 받고 setLatestEthPrice()함수를 불러서 아래 세 가지를 인자로 넘겨준다
  1. 이더 가격
  2. 리퀘스트를 시작한 컨트랙트의 주소
  3. 리퀘스트의 아이디
 function setLatestEthPrice(uint256 _ethPrice, address _callerAddress,   uint256 _id) public onlyOwner {
    require(pendingRequests[_id], "This request is not in my pending list.");
    delete pendingRequests[_id];
  }
  • 리퀘스트 아이디가 true 인지 확인힌다.(==true 안해도 저 자체가 boolean이라 pendingRequests[_id]만 사용)
  • 넘겨받으면 pendingRequests에서 해당 아이디 기록을 지워야 한다.

인터페이스를 이용해 callback 작동시킴

 function setLatestEthPrice(
        uint256 _ethPrice,
        address _callerAddress,
        uint256 _id
    ) public onlyOwner {
        require(
            pendingRequests[_id],
            "This request is not in my pending list."
        );
        delete pendingRequests[_id];
          //컨트랙트 인스턴스화
        CallerContracInterface callerContractInstance;
        callerContractInstance = CallerContracInterface(_callerAddress);
          //콜백 함수 작동시킴
        callerContractInstance.callback(_ethPrice, _id);
          //이벤트 트리거
        emit SetLatestEthPriceEvent(_ethPrice, _callerAddress);
    }
  • 컨트랙트의 인터페이스를 인스턴스화시킴
  • 인스턴스화된 컨트랙트의 callback함수를 작동시켜 이더리움 가격과 리퀘스트의 아이디를 넘긴다.
profile
devlog

1개의 댓글

comment-user-thumbnail
2021년 9월 13일

cat_dev님 안녕하세요,
헤드헌팅사 유니코써치의 김만규 컨설턴트입니다.

블록체인 관련 Job Position JD 중 모르는 사항을 공부 중
cat_dev님의 블로그에서 좋은 자료를 발견, 덕분에 공부하는데 어려움이 다소 해소되었습니다.

감사드리며, 이후에도 좋은 글 기대하겠습니다.
또한 혹시 이직을 준비하고 계시다면 제가 도움 받았듯,
cat-dev님의 이직과정이 즐거운 경험이 될 수 있도록 최선을 다해 지원하겠습니다.

감사합니다.

  • 유니코써치 김만규 드림 -

Tel) 010 4913 7163
Email) leo@unicosearch.com
Linkedin) https://www.linkedin.com/in/no1recruiting/

답글 달기