Writing an oracle from scratch (3)

This blog is organized at cryptozombies.io/zh/lesson
To view the original tutorial, please refer to the above link, this blog is a personal record!

Writing an oracle from scratch (3)

1. Overview

In the oracle function we have implemented earlier, there is only one oracle contract, and only one API is used to obtain data. This is obviously not safe and reliable enough! Next, we will focus on improving the decentralization of the oracle! (Get data from multiple apis from multiple oracles!)

In the code part, the part to be modified is only the EthOracleContract.sol contract

2、EthOracleContract.sol

pragma solidity 0.5.0;

import "openzeppelin-solidity/contracts/access/Roles.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./CallerContractInterface.sol";

contract EthPriceOracle {
    
    
    using Roles for Roles.Role;
    Roles.Role private owners;
    Roles.Role private oracles;

    using SafeMath for uint256;

    uint private randNonce = 0;
    uint private modulus = 1000;
    uint private numOracles = 0;
    uint private THRESHOLD = 0;
    mapping (uint256 => bool) pendingRequests;

    struct Response {
    
    
        address oracleAddress;
        address callerAddress;
        uint256 ethPrice;
    }
    mapping (uint256=>Response[]) public requestIdToResponse;

    event GetLatestEthPriceEvent(address callerAddress,uint id);
    event SetLatestEthPriceEvent(uint256 ethPrice,address callerAddress);
    event AddOracleEvent(address oracleAddress);
    event RemoveOracleEvent(address oracleAddress);
    event SetThresholdEvent (uint threshold);

    constructor (address _owner) public {
    
    
        owners.add(_owner);
    }

    function addOracle(address _oracle) public {
    
    
        require(owners.has(msg.sender),"Not an owner!");
        require(!oracles.has(_oracle),"Already an oracle!");
        oracles.add(_oracle);
        numOracles++;
        emit AddOracleEvent(_oracle);
    }

    function removeOracle(address _oracle) public {
    
    
        require(owners.has(msg.sender),"Not an owner!");
        require(oracles.has(_oracle),"Not an oracle!");
        require(numOracles > 1,"Do not remove the last oracle!");
        oracles.remove(_oracle);
        numOracles--;
        emit RemoveOracleEvent(_oracle);
    }

    function setThreshold (uint _threshold) public {
    
    
        require(owners.has(msg.sender), "Not an owner!");
        THRESHOLD = _threshold;
        emit SetThresholdEvent(THRESHOLD);
    }

    // 该函数供caller调用,实现发起一个数据请求!
    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);
        return id;
    }

    // 调用该函数将ethPrice写入callerContract合约中
    function setLatestEthPrice(uint256 _ethPrice,address _callerAddress,uint256 _id) public {
    
    
        require(oracles.has(msg.sender), "Not an oracle!");
        require(pendingRequests[_id],"This request is not in my pending list.");
        Response memory resp;
        resp = Response(msg.sender,_callerAddress,_ethPrice);
        requestIdToResponse[_id].push(resp);
        uint numResponses = requestIdToResponse[_id].length;
        if (numResponses == THRESHOLD) {
    
    
            uint computedEthPrice = 0;
            for(uint f = 0;f < requestIdToResponse[_id].length;f++) {
    
    
                computedEthPrice = computedEthPrice.add(requestIdToResponse[_id][f].ethPrice);
            }
            computedEthPrice = computedEthPrice.div(numResponses);
            delete pendingRequests[_id];
            delete requestIdToResponse[_id];
            CallerContractInterface callerContractInstance;
            callerContractInstance = CallerContractInterface(_callerAddress);
            callerContractInstance.callback(computedEthPrice, _id);
            emit SetLatestEthPriceEvent(computedEthPrice, _callerAddress);
        }
    }
}

In this part, we added rights management of owners and oracles.
Introduced the Roles library in openzeppelin-solidity
to add multiple oracle contracts, and deleted the content of the onlyOwner function modifier in (1), and used require in the function to determine whether it is an owner or an oracle

And in the setLatestEthPrice function, the THRESHOLD variable is added, indicating that a certain number of oracle machines return the eth price before writing the result back to the caller contract

Guess you like

Origin blog.csdn.net/qq_45469783/article/details/123365116