预言机Truora学习笔记5--Truora-Service服务端代码分析

本文分析Truora-Service服务端java,目标是梳理出OracleCore合约查找创建机制、事件监听机制、url访问机制、数据回写机制, 以后创建自己的预言机服务器就了如指掌了。

代码下载路径: git clone GitHub - WeBankBlockchain/Truora-Service

1  配置文件

项目配置文件build.gradle中的配置有这些内容:

implementation 'org.fisco-bcos:solcJ:0.6.10.0'

implementation 'org.fisco-bcos.java-sdk:fisco-bcos-java-sdk-v3:3.0.1'

2 OracleCore合约查找创建机制

服务启动阶段, 执行:

Bcos3ClientConfig  自动装配,读取配置文件conf/application-fiscobcos3.yml   

     读出platform: fiscobcos3, 装配类EventRegisters,按照chainId分类读取groupId。

Bcos3EventRunner   init()

     检查eventRegisters.startOracleCore==true?  

   true就开始执行  oracleWorker.init(eventRegister),调用父类的init():

         AbstractContractWorker  init()  

                          initContract()  

                                loadOrDeployContract() : 读取数据库中记录查找ORACLE_CORE类型,

                                     找到记录,读取合约地址,检查有效性:--->

                                        this.isContractAddressValid(eventRegister, contractAddress)     这里面直接用OracleCore类加载地址生成合约实例。

                                     没找到记录,表示不存在合约,开始部署, 部署成功后写入数据库

                                        OracleCoreWorker  deployContract()


3 OracleCore合约事件监听

紧接着上一步合约地址初始化oracleWorker.init(eventRegister),开始监听事件初始化

oracleCoreEventCallback.init(oracleWorker);

     Bcos3EventCallback   init()

           registerEventListener();   

           读取数据库历史记录,找到最后一条记录的区块号,+1后赋值给from,表明监听开始的区块号。

           subcriber.subscribeEvent(eventSubParams,this);   组装监听事件参数,注册,自己就是回调处理对象,实现了处理方法onReceiveLog

           onReceiveLog()  收到事件,异步处理,交给

                 AbstractContractWorker    processBatchLogs()    处理一批log,

                                      processSingleLog(eventLog);          处理一条log

                                           处理逻辑:检查数据库中是否已经存在requestId,存在表示处理过这条事件,丢弃。

                                           调用 OracleCoreWorker   processLog()   去链下获取各种资源并回写链上

                                                  sourceCrawlerFactory.handle()     

                                                  URLCrawler   handle()  发起http调用。

                                            fulfill()  查询得到的结果写回预言机合约,写前先查询合约中是否存在了requestId结果,目的是防止重复写入。

                                                  直接用OracleCore类调用方法fulfillRequest完成交易,最后检查交易结果,写入

                                            执行结果写入History数据库 

                                            this.updateReqHistory(requestId, reqStatus, errorMsg, result);        

4 url访问机制

关键的数据源爬虫工厂类:SourceCrawlerFactory 

设计思想是一个简单的插件化机制,便于在扩展更多的的资源获取方式时,对接到事件回调流程里。

* 即:EventWorker收到链上预言机事件,则调用这里的接口,传入事件里和数据源有关的参数

* Factory根据名称等信息,确定实例化哪一个bean去调用外部资源,如“UrlCrawler”去获取,并返回结果,供worker去上链

* 初步拟定进出的参数都是简单的字符串,可以打成json格式

* * 如{name="Url",url="http://www.xyz.com"},

* 只需要包含有name,则可以定位到bean,然后json的解析可以由bean自由发挥。

*规则: bean的名字必须是 [XXX]Crawler, 如URLCrawler,注解要指明名字: @Service("URLCrawler") ,可选:@Scope("prototype")

实际上是在 URLCrawler   handle()  发起http调用。

两个调用方法,最终调用到具体的爬虫实现类.handle().

public String handle(String inputStr)

public String handle(String name, String inputStr)

爬虫实现类:

HashUrlCrawler:通过url访问外部网页,将返回的资源内容全部打成hash。关键是通过cryptoSuite.hash(httpResponse)。

LocalRandomCrawler:一个本地生成伪随机数的桩,主要用来做测试。

URLCrawler:通过url访问外部网页,返回的结果。  

    使用httpService.getHttpResultAndParse(httpUrl, format, path);

// url = "https://www.random.org/integers/?num=100&min=1&max=100&col=1&base=10&format=plain&rnd=new"

// url = "plain(https://www.random.org/integers/?num=100&min=1&max=100&col=1&base=10&format=plain&rnd=new)[1]";

// url = "json(https://api.exchangerate-api.com/v4/latest/CNY).rates.JPY";

format格式:

  •  json-- 返回结果解析成json,然后按照附加的字段读取对应的数据。详细的请看JsonPath说明

com.jayway.jsonpath

Class JsonPath

java.lang.Object

com.jayway.jsonpath.JsonPath



public class JsonPath

extends java.lang.Object

JsonPath is to JSON what XPATH is to XML, a simple way to extract parts of a given document. JsonPath is available in many programming languages such as Javascript, Python and PHP.

JsonPath allows you to compile a json path string to use it many times or to compile and apply in one single on demand operation.

Given the Json document:



String json =

"{

    "store":{

        "book":[

            {

                "category":"reference",

                "author":"Nigel Rees",

                "title":"Sayings of the Century",

                "price":8.95

            },

            {

                "category":"fiction",

                "author":"Evelyn Waugh",

                "title":"Sword of Honour",

                "price":12.99

            }

        ],

        "bicycle":{

            "color":"red",

            "price":19.95

        }

    }

}";



A JsonPath can be compiled and used as shown:

JsonPath path = JsonPath.compile("$.store.book[1]"); List<Object> books = path.read(json);

Or:

List<Object> authors = JsonPath.read(json, "$.store.book[*].author")

If the json path returns a single value (is definite):

String author = JsonPath.read(json, "$.store.book[1].author")

  Gradle: com.jayway.jsonpath:json-path:2.5.0 (json-path-2.5.0.jar)

  •  plain-- 返回结果解析成数组,url后面的[1]指明了元素index,直接读取index元素数据。

  • url-- 无需解析,直接返回结果。


5 数据回写机制

服务器端执行完监听事件请求,得到的外界URL返回数据,这时必须要把这个数据写入到OracleCore合约中,之后链上合约才能读取到数据,正常运行相关功能。

OracleCoreWorker   fulfill()  工作流程:

读取OracleCore合约地址,

加载OracleCore合约地址,生成oracleCore实例。

先查询合约中是否存在了requestId结果,已经存在结果(可能是被处理过了,或者超时了)就不再重复写入。这一步目的是防止重复写入,减少一个错误的交易。

直接用OracleCore类调用方法fulfillRequest完成交易,得到收据receipt。

      检查交易结果:成功, 输出log信息;

                              失败,区分交易错误和处理错误两种类型,分别输出log信息。

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值