从零开始写预言机(三)

本博客整理于 cryptozombies.io/zh/lesson
查看原教程请参考如上链接,本博客做个人记录!

从零开始写预言机(三)

1、概览

在前面我们已经实现的预言机功能里面,只有一个预言机合约,并且只从一个api中获取数据。这显然是不够安全可靠的!接下来我们将着力于提升该预言机的去中心化性!(从多个预言机中获取来自多个api中的数据!)

代码部分,要修改的部分仅为EthOracleContract.sol合约

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);
        }
    }
}

在这部分里面,我们加入了owners与oracles的权限管理。
引入了openzeppelin-solidity中的Roles库
可以添加多个预言机合约,并且删除了(一)中的有关onlyOwner的函数修饰符的内容,改用在函数内用require判断是否是owners、是否是oracle

并且在setLatestEthPrice函数中,添加了THRESHOLD的变量,表明有一定数量的预言机返回eth价格后才将结果写回调用者合约

猜你喜欢

转载自blog.csdn.net/qq_45469783/article/details/123365116
今日推荐