if resData == nil {
res,
query := ethereum.FilterQuery{
}
queryInfo.QueryId,
}
}
这段时间以太坊网络较量拥堵,导致手续费居高不下。对付我们Oracle处事来说,节减Gas是很重要的一个优化偏向。
CallbackAddr common.Address
}
}
func (e *EventWatch) sendQueryRequest(reqData *QueryRequest, resParamType string) (interface{}, error) {
return fmt.Errorf(“[SendQueryResponse] Transact failed: %v”, err)
if err := e.subscribeEvent(); err != nil {
回调模块相比拟力简朴,首先将Oracle合约实例化了一个BoundContract工具,然后挪用Transact要领发送生意业务。个中第一个参数是利用私钥实例化的一个TransactOpts工具。
case “bytes”:
queryInfo := &OracleQueryInfo{}
处事开启后,首先会通过ws协议的jsonrpc,在上注册事件订阅,订阅乐成后开启一个for轮回,吸收并处理惩罚事件动静。
三、事件订阅
stateCode,
case “uint256”:
return nil, fmt.Errorf(“[sendQueryRequest] NewRequest failed: %v”, err)
Oracle后端处事整体包括事件订阅模块、查询模块和回调模块,架构如下图所示。
事件订阅的焦点是通过ethclient的SubscribeFilterLogs要领,个中query参数是订阅的过滤条件。个中五、回调模块
return
// sendQueryResponse 将查询到的功效发送给客户端合约指定要领
queryInfo.CallbackFUN,
if err != nil {
responseName = OracelResponseBytesName
func (e *EventWatch) dealQuery(vLog types.Log) error {
}
if err != nil {
logs.Error(“[SubscribeEvent]fail to subscribe event:”, err)
for _, paramName := range keys {
var resValue interface{}
default:
logs.Error(“[dealEvent] Subscription err: “, err)
return fmt.Errorf(“[SendQueryResponse] unsupport response data type”)
events := make(chan types.Log)
至此,我们的V1版的Oracle处事已开拓完成,处事已能满意根基需求,但尚有一些方面需要进一步优化,我这里列出了三点。
return nil, fmt.Errorf(“[ParseResponeData] unsupport response data type %s”, resParamType)
func ParseResponeData(repData []byte, keys []string, resParamType string) (interface{}, error) {
针对这种环境,我的思路是对Nonce举办托管:
查询大概失败,这里需要增加失败重试机制,代码较量简朴,就不写出来了。
go e.dealQuery(vLog)
resData, err := simplejson.NewJson(repData)
•引入动态GasPrice,可以从https://ethgasstation.info网站中获取及时的GasPrice•指定GasLimit,防备由于合约问题耗损过多Gas•余额查抄,防备由于余额不敷造成生意业务失败,挥霍了手续费•吸收回调数据的用户合约要领只管简朴,疏散业务逻辑
common.HexToAddress(e.Config.OracleContractAddress),
ResponseParams []string `json:”responseParams,omitempty”`
// ParseResponeData 理会链下获取到的数据,提取用户所需要的字段,并转换为对应的数据范例
Topics: [][]common.Hash{
return nil, fmt.Errorf(“[sendQueryRequest] read response data failed: %v”, err)
if err != nil {
// start monitor oracle contract event
for {
3、支持http协议jsonrpc
select {
logs.Trace(“[SendQueryResponse] call back tx:”, transaction.Hash().Hex())
本篇是中篇,主要利用go语言开拓实现Oracle的后端处事。
}
},
resData = resData.Get(paramName)
func (e *EventWatch) Start() {
代码如下所示。
case err := <-e.Subscription.Err():
}
body, err := ioutil.ReadAll(res.Body)
一、文章布局
case vLog := <-e.EventChan:
e.Subscription = sub
}
resValue = big.NewInt(int64(resUint64Value))
// sendQueryRequest 按照客户端指定的查询地点发送请求
type OracleQueryInfo struct {
return nil, fmt.Errorf(“[ParseResponeData] unmarshal response data failed:%v”, err)
return nil
Requester common.Address
}
有的网络节点没有开启ws处事,而利用http协议的网络jsonrpc又无法直接订阅事件。这时可以采纳迂回计策,模仿事件订阅,详细思路如下:
switch resParamType {
这里我的思路是可以从以下几个方面优化:
}
•在缓存(内存或redis等)中维护账号对应的Nonce•每次提倡生意业务时,从缓存中获取,每获取一次,缓存中的Nonce累加1•缓存中的Nonce按期和链长举办校对和同步•对付大概呈现的空洞环境,利用空生意业务填补
return nil, err
}
文中的Oracle处事完整代码地点:https://github.com/six-days/ethereum-oracle-service
}
func (e *EventWatch) dealEvent() {
transaction, err := e.BoundContract.Transact(e.TransactOpts, responseName, in…)
if err != nil {
responseName = OracelResponseUint256Name
}
return fmt.Errorf(“[dealQuery] unmarshal query data failed:%v”, err)
}
事件订阅必需利用ws协议的jsonrpc,http协议的jsonprc无法订阅事件。
case “uint256”:
in := []interface{}{
Transact要领源码详见:https://github.com/six-days/go-ethereum/blob/master/accounts/abi/bind/base.go
queryInfo.CallbackAddr,
return resValue, nil
这里利用go-simplejson库将查询功效举办json理会,而且提取用户指定所需要的字段,将字段转换为用户合约中回调要领吸收的数据范例。
1、日志理会
}
1、Nonce托管
References
reqData := &QueryRequest{}
}
if coverErr == nil {
e.dealEvent()
Fee *big.Int
各人对付优化有其他思路或疑问,接待留言探讨。
}
}
}
查询请求较量简朴,就是按照用户提供的url发送请求。代码如下所示。
在TransactOpts工具中可以设置nonce、gasLimit、gasPrice等值,假如不指定,Transact要了解本身增补上。除此之外,Transact要领也会挪用TransactOpts工具的Signer要领对动静举办签名。
2、Gas优化
事件日志理会我们用go-ethereum的abi模块的Unpack要领,将日志理会为我们界说好的布局体。
代码如下所示。
return err
switch resParamType {
URL string `json:”url,omitempty”`
if err != nil {
queryRes, err := ParseResponeData(body, reqData.ResponseParams, resParamType)
},
}
•上篇:Oracle简介及合约实现[1]•中篇:利用go语言开拓Oracle处事•下篇:抽奖合约挪用Oracle处事示例
}
}
Raw types.Log // Blockchain specific contextual infos
CallbackFUN string
}
logs.Trace(“[sendQueryRequest] get “, reqData.URL, ” response is: “, string(body))
}
func (e *EventWatch) sendQueryResponse(res interface{}, stateCode uint64, queryInfo *OracleQueryInfo, resParamType string) error {
}
if err = json.Unmarshal(queryInfo.QueryData, reqData); err != nil {
case “bytes”:
}
{e.OracleABI.Events[OracelEventName].ID()},
return nil, fmt.Errorf(“[ParseResponeData] response data type %s error:%v”, resParamType, err)
return fmt.Errorf(“[dealQuery] unpack event log failed:%v”, err)
在高并发的环境下,必定会呈现多笔生意业务Nonce值沟通的环境,后提倡生意业务包围前生意业务,造成前生意业务失败。
return nil, fmt.Errorf(“[sendQueryRequest] http get request failed: %v”, err)
本文将通过上、中、下三篇文章教育各人一步步开拓实现一其中心化的Oracle处事,并通过一个抽奖合约演示如何利用我们的Oracle处事。文章内容布置如下:
func (e *EventWatch) subscribeEvent() error {
if coverErr != nil {
res, err := http.DefaultClient.Do(req)
在回调模块中,挪用合约时,我们并没有指定提倡生意业务账号的Nonce值,而是由Transact要领在每次提倡生意业务时,动态计较。这就会限制我们生意业务的并发。
六、可以优化的处所
在上篇中,,我们实现了一个通用的Oracle合约,其主要有一个吸收用户请求的Query要领;回挪用户合约的Response要领和一个供Oracle后端处事订阅的QueryInfo事件。
•开启网络区块监控•监控到有新区块发生,查询区块中的日志•假如有我们Oracle合约发生的查询日志,则进入后续的查询和回调流程
•Addresses是Oracle合约地点;•Topics参数是过滤主题,是一个二维数组,这里我们的主题只指定了事件的名称。
err := e.OracleABI.Unpack(queryInfo, OracelEventName, vLog.Data)
var coverErr error
default:
return nil
req, err := http.NewRequest(“GET”, reqData.URL, nil)
二、处事架构
resUint64Value, coverErr := resData.Uint64()
var responseName string
e.EventChan = events
代码如下所示。
}
3、功效理会
2、查询请求
sub, err := e.Client.SubscribeFilterLogs(context.Background(), query, events)
回调也大概失败,处事对sendQueryResponse要领的挪用也增加了失败重试机制。
type QueryRequest struct {
e.subscribeEvent()
四、查询模块
}
if err != nil {
resValue, coverErr = resData.Bytes()
[1] Oracle简介及合约实现: https://learnblockchain.cn/article/1150回调模块代码如下所示。
QueryData []byte
下篇中,我将以一个抽奖合约为示例,先容如何利用我们开拓的Oracle处事来对抽奖合约提供一个随机数。
Addresses: []common.Address{
QueryId [32]byte
return queryRes, nil
if err != nil {
if err != nil {
// 处理惩罚查询请求并回调
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。