on-chain Oracle會驗證是否已達到最小數量的相等響應,如果已達到,則會發出一個事件,表明其已就價值達成共識,以便查詢Oracle的客戶機智慧合約知道其已收到響應。
On-chain Oracle實施
我們用約定的條款定義Oracle合同:最低法定人數和Oracle總數。對於這個例子,有三個利益相關者,為了達成共識,3箇中的2個必須提供相同的答案。
pragma solidity >=0.4.21 <0.6.0;
contract Oracle {
Request[] requests; //list of requests made to the contract
uint currentId = 0; //increasing request id
uint minQuorum = 2; //minimum number of responses to receive before declaring final result
uint totalOracleCount = 3; // Hardcoded oracle count
}
然後我們新增Request Struct,它將儲存請求:
// defines a general api request
struct Request {
uint id; //request id
string urlToQuery; //API url
string attributeToFetch; //json attribute (key) to retrieve in the response
string agreedValue; //value from key
mapping(uint => string) anwers; //answers provided by the oracles
mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted)
}
現在我們可以建立公共函式createRequest,客戶端智慧合約(任何想要使用oracle服務的合同)都會呼叫:
function createRequest (
string memory _urlToQuery,
string memory _attributeToFetch
)
public
{
uint lenght = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));
Request storage r = requests[lenght-1];
// Hardcoded oracles address
r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;
r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;
r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;
// launch an event to be detected by oracle outside of blockchain
emit NewRequest (
currentId,
_urlToQuery,
_attributeToFetch
);
// increase request id
currentId++;
}
該功能包含利益相關者之間協議的重要部分。 受信任參與最終解決方案的帳戶的地址。並且發出被off-chain oracle監聽的事件NewRequest。
//event that triggers oracle outside of the blockchain
event NewRequest (
uint id,
string urlToQuery,
string attributeToFetch
);
在監聽此事件後,off-chain Oracle將呼叫公共函式updateRequest。
//called by the oracle to record its answer
function updateRequest (
uint _id,
string memory _valueRetrieved
) public {
Request storage currRequest = requests[_id];
//check if oracle is in the list of trusted oracles
//and if the oracle hasn't voted yet
if(currRequest.quorum[address(msg.sender)] == 1){
//marking that this address has voted
currRequest.quorum[msg.sender] = 2;
//iterate through "array" of answers until a position if free and save the retrieved value
uint tmpI = 0;
bool found = false;
while(!found) {
//find first empty slot
if(bytes(currRequest.anwers[tmpI]).length == 0){
found = true;
currRequest.anwers[tmpI] = _valueRetrieved;
}
tmpI++;
}
uint currentQuorum = 0;
//iterate through oracle list and check if enough oracles(minimum quorum)
//have voted the same answer has the current one
for(uint i = 0; i < totalOracleCount; i++){
bytes memory a = bytes(currRequest.anwers[i]);
bytes memory b = bytes(_valueRetrieved);
if(keccak256(a) == keccak256(b)){
currentQuorum++;
if(currentQuorum >= minQuorum){
currRequest.agreedValue = _valueRetrieved;
emit UpdatedRequest (
currRequest.id,
currRequest.urlToQuery,
currRequest.attributeToFetch,
currRequest.agreedValue
);
}
}
}
}
}
此函式將首先檢查呼叫者是否是預定義地址之一。 然後它會檢查oracle沒有投票,如果是,它將儲存oracle答案。 然後它將檢查該答案是否至少由所需的最低法定人數提供。 如果是這樣,那麼我們就結果達成一致,並將發出一個事件,即UpdatedRequest,以警告客戶合同結果。
//triggered when there's a consensus on the final result
event UpdatedRequest (
uint id,
string urlToQuery,
string attributeToFetch,
string agreedValue
);
Off-chain Oracle實施
這是更簡單的部分,它是可以監聽發出的區塊鏈事件和查詢API的任何服務。
off-chain Oracle使用web3監聽鏈上Oracle發出的事件,並查詢請求的api,解析檢索到的json以獲取請求的金鑰,並呼叫公共函式updateRequest。
您可以在github上找到off-chain oracle所有利益相關方應該部署的此服務的程式碼。https://github.com/pedroduartecosta/blockchain-oracle/tree/master/off-chain-oracle
這種實現允許不依賴於一方作為唯一一個查詢API的真實來源,而是讓多方就一個結果達成一致。它也是一個非常靈活的服務,因為它可以查詢任何公共JSONAPI,允許在大量的用例中使用。