

# 一、需求描述  

## 1.需求背景：
　　为保证数据的公平公正性，在区块链上提供权威数据发布合约。满足以下需求：

    合约提供录入和查询接口。
    合约录入时对数据的key和value定义好标准的格式。
    合约是否要满足一定的经济模型，惩罚机制（一期可以不实现，后面再加入）

## 2.实现点：
    发布者的地址需要通过superManager添加，调用我们系统manage合约。
    数据发布的key要遵循一定的格式，比如游戏类的格式要满足一定的前缀（发布者地址+ 运营特征值+游戏类别 等）
    数据发布的时候要能输入数据来源描述（比如：数据来源于新浪体育）
    数据发布的value要根据现有的业务做一定的抽象，这块一期可以先考虑下，不用实现的很完备。 一期可以用json格式，数据提供方和开发方可以事先先约定好。
    合约对外提供查询接口供具体的应用合约调用， 具体的应用合约只查询满足条件的key，获取数据做相应的运算。
    数据的发布需要先预发布，再审核后切换成正式发布。（类似于token的预创建和完成这两步）


# 二、流程及状态机示意

## 1.流程时序图  
![Oracle流程时序图](./resource/oracle/Oracle-Seq.jpg)  

## 2.状态机图  

![Oracle状态机图](./resource/oracle/Oracle-State.jpg)  

## 3.说明　　

1.合约提供基础的数据受限发布上链的能力，通过授权特定地址，保证数据正确可靠。（运营方为自身业务持续发展考虑，会保证数据正确，并为数据失误负责）  
2.事件发布和结果发布分为两个过程，这样可以方便运营方从事件发布中获取竞猜或者菠菜的事件源，在结果出现时，提供正确结果，供菠菜合约自动开奖。  
3.事件多来自现实世界，结果可验证，如果出现结果错误，运营方需要承担责任。  
4.考虑现实世界，有些事件会因为不可抗力（自然灾害、战争等），导致事件最终未发生，没有结果，则Oracle合约提供撤销事件的接口。  
5.对于结果预发布到链上供检验，如果有问题，会有人提出来，管理员或者特定权限的地址可以撤销预发布结果。  
6.对于预发布结果确认正确无误，可由管理员或者特定权限的地址正式发布。正式发布后的结果不能修改。  
7.数据结果发布中，json格式中可以通过字段标记数据来源等必要信息。  
8.第一期合约存储数据主要是json格式，json格式的具体字段可以根据具体的事件类型来进行设计，以满足不同的菠菜、竞猜合约的需要。  
9.最终发布的结果一般来自于预发布结果，超级管理员也可以直接发布结果。  
10.该预言机合约也可以针对比特币区块链的未来区块Hash进行定期发布，比如发布一个event，是发布１０分钟以后的产生的高度为５５３３５０的区块Ｈａｓｈ，那么该区块生成后，其ｈａｓｈ可发布在Chain33上，一些博彩合约的随机数可以使用该值，且这个值不可预测，可以验证，客观公证。但由于其实时性，只可用于实时性不高的一些博彩游戏使用。该事件发布可以和比特币网络互通，做成自动定时发布未来区块Hash，作为一个外部引入的随机源，满足一部分业务的需要。  

## 4.数据存储

```json
Action:
	eventPublish
	eventAbort
	resultPrePublish
	resultAbort
	resultPublish

Key:
        mavl-oracle-id                             //stateDB, 存储event及id,status,result等信息，可根据id进行查询。  
        LODB-oracle-status-index:%d:%018d          //localDB, 按状态存储，,比如未公布结果的事件，已公布结果的事件等。主键构成中有index可以支持分页查询，可以按状态查询。  
        LODB-oracle-addr-status-index:%s:%d:%018d　//localDB, 按创建者地址及状态进行查询，主键构成中有index可以支持分页查询。  
        LODB-oracle-type-status-index:%s:%d:%018d　//localDB, 按事件类型及状态进行查询，主键构成中有index可以支持分页查询。 比如查询足球.英超.的所有未出结果的事件，利用这些事件进行竞猜等。
        ......
```       

## 5.应用举例

场景１：
2019年1月１号，addr通过Oracle合约发布事件：
```json
Event {
"type":"football",
"subType":"Premier League",
"time":"2019-1-21 15:30:00",
"team1":"ChelSea",
"team2":"Manchester",
"resultType":"score"
}
```
该事件表示：未来将公布【足球】【英超】【２０１９年１月２１日１５：３０：００】【切尔西对阵曼彻斯特】的足球比赛，结果以比分公布。　　

基于该时间，竞猜合约中可以发布竞猜游戏Ａ，让玩家猜结果（比如让球输赢）或者赌输赢（谁输谁赢）等。　　

当结果出来后，addr预发布结果，比如：比分为切尔西：阵曼彻斯特＝２：１，公布到链上一段时间后，如果无人对结果提出异议，则addr正式发布该结果（正式发布的结果不能撤销）。　　

竞猜游戏Ａ使用最终发布结果，对参与的玩家进行输赢判断及结算。　　


场景２：
addr定期通过Oracle合约发布比特币区块链未来生成区块的hash，比如周期性提前一天或者若干时间生成类似如下事件
```json
Event {
"type":"bitcoin",
"subType":"blockhash",
"time":"2018-12-12 07:30:00",
"height":"553450",
"resultType":"hash"
}
```
该事件表示：未来将公布【bitcoin】【blockhash】【大概时间2018-12-12 07:30:00之后】【区块高度为553450】的hash值。  
有一些博彩游戏，对实时性要求不高，比如说未来开奖的游戏Ｂ，要使用随机数，可以使用该事件结果作为作为随机数计算开奖结果。  
当bitcoin的区块高度达到设定高度553450后，addr将其生成的blockhash进行预发布到区块链全网，确认无误，无人提出异议，过一段时间后addr正式发布该结果。  
游戏Ｂ使用最终发布的blockhash计算开奖结果，对参与的玩家进行输赢判断及结算。      
  
说明：  
对于使用预言机发布数据的游戏合约，本身对预言机要发布的具体事件有具体的了解，知道数据如何在自己的游戏中使用。比如足球比赛，给出了开赛时间，则游戏设定要提前终止投注，保证参与公平性。      
再比如对于比特币的未来区块hash做开奖随机数的场景，游戏合约要知道未来生成区块hash的时间是一个估算值，数据发布者会实时调整确保估算尽量准确，但由于区块生成时间本身并不固定，所以游戏合约要考虑时间波动因素，确保提前结束投注，保证参与公平性。

