从零开发区块链应用(十四)--以太坊交易哈希查询

2022-02-22 18:00:24 浏览数 (1)

杰哥的技术杂货铺[1]

一、查询以太坊交易

当上述事件在合约中调用后,我们通过其交易hash获取交易信息。从以太坊得到一条交易信息的方式有两种:

  • eth_getTransactionByHash: :返回指定交易对应的交易信息
  • eth_getTransactionReceipt :返回指定交易对应的收据信息

1.1 获取以太坊交易信息

GetTransactionByHash 获取交易信息

代码语言:javascript复制
// 定义一个方法,接收参数为交易哈希,返回参数为接口类型
func (eth *Http) GetTransactionByHash(hash string) (interface{}, error) {
// 判断交易哈希长度是否为66位
 if len(hash) != 66 {
 // 如果交易哈希长度不是66位,则返回交易哈希散列长度错误
  return nil, errors.New("GetTransactionByHash hash length  wrong")
 }
 // 定义一个接口的变量,值为交易哈希
 args = []interface{}{hash}
 // 调用以太坊rpc,查询交易哈希
 params := NewHttpParams("eth_getTransactionByHash", args)
 resBody, err := eth.rpc.HttpRequest(params)
 if err != nil {
  return nil, err
 }
 // 返回一个解析后的交易信息结果
 return eth.ParseJsonRPCResponse(resBody)
}
  • 以太坊rpc调用参数拼接方法:NewHttpParams
代码语言:javascript复制
func NewHttpParams(method string, args []interface{}) string {
 id := common.GetRandString(16)
 request := &Request{
  ID:      id,
  Mthd:    method,
  Args:    args,
  Version: "2.0",
 }
 rb, _ := json.Marshal(request)
 return string(rb)
}
  • 请求结果解析:ParseJsonRPCResponse
代码语言:javascript复制
// ParseJsonRPCResponse jsonrpc格式返回结果解析
func (eth *Http) ParseJsonRPCResponse(resBody []byte) (interface{}, error) {
 response := new(apicommon.Response)
 err := json.Unmarshal(resBody, &response)
 if err != nil {
  logger.Warn("resBody", resBody, string(resBody))
  return nil, errors.New("ParseJsonRPCResponse Unmarshal err")
 }
 if response.Error != nil { //  && response.Error.Code != 3
  return nil, errors.New(response.Error.Msg)
 }
 return response.Result, nil
}

1.2 获取以太坊交易回执信息

GetTransactionReceipt 获取交易票据

代码语言:javascript复制
// 定义一个方法,接收参数为交易哈希,返回参数为接口类型
func (eth *Http) GetTransactionReceipt(hash string) (interface{}, error) {
 // 判断交易哈希长度是否为66位
 if len(hash) != 66 {
 // 如果交易哈希长度不是66位,则返回交易哈希散列长度错误
  return nil, errors.New("GetTransactionReceipt hash length  wrong")
 }
 // 定义一个接口的变量,值为交易哈希
 args = []interface{}{hash}
 // 调用以太坊rpc,查询交易哈希
 params := NewHttpParams("eth_getTransactionReceipt", args)
 resBody, err := eth.rpc.HttpRequest(params)
 if err != nil {
  return nil, err
 }
 // 返回一个解析后的交易信息结果
 return eth.ParseJsonRPCResponse(resBody)
}
  • 以太坊rpc调用参数拼接方法:NewHttpParams
代码语言:javascript复制
func NewHttpParams(method string, args []interface{}) string {
 id := common.GetRandString(16)
 request := &Request{
  ID:      id,
  Mthd:    method,
  Args:    args,
  Version: "2.0",
 }
 rb, _ := json.Marshal(request)
 return string(rb)
}
  • 请求结果解析:ParseJsonRPCResponse
代码语言:javascript复制
// ParseJsonRPCResponse jsonrpc格式返回结果解析
func (eth *Http) ParseJsonRPCResponse(resBody []byte) (interface{}, error) {
 response := new(apicommon.Response)
 err := json.Unmarshal(resBody, &response)
 if err != nil {
  logger.Warn("resBody", resBody, string(resBody))
  return nil, errors.New("ParseJsonRPCResponse Unmarshal err")
 }
 if response.Error != nil { //  && response.Error.Code != 3
  return nil, errors.New(response.Error.Msg)
 }
 return response.Result, nil
}

二、以太坊交易确认数

以太坊和比特币一样,都有一个最长链的概念,因此也有一个交易确认数的概念。当一个以太坊交易所在区块被新加入区块链时,该交易的确认数为1,之后每增加 一个区块,该交易的确认数加1。显然,一个以太坊交易的确认数越多,就意味着 该交易在区块链中埋的越深,就越不容易被篡改。那么,应该如何获取一个以太坊 交易的确认数?

2.1 使用rpc获取以太坊交易确认数

要获取一个以太坊交易的确认数,需要使用两个RPC调用:

  • eth_getTransactionReceipt:获取交易收据
  • eth_blockNumber:获取最新区块号

首先利用eth_getTransactionReceipt调用获取指定的交易收据,例如,下面的命令获取交易0xbca39c1f778fcae9e86b513b6e18ed4b0a04b8e0ad5a0c1c1c81788ab1e94bbd的收据:

代码语言:javascript复制
curl -X POST --data '{
  "jsonrpc":"2.0",
  "method":"eth_getTransactionReceipt",
  "params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],
  "id":1}' http://localhost:8545

在结果中可以获取该交易所在区块编号:

代码语言:javascript复制
{
"id":1,
"jsonrpc":"2.0",
"result": {
     ...
     blockNumber: '0xd70aca', // 区块14093002
     ...
  }
}

然后就可以在随后的任意时刻使用eth_blockNumber调用来获取当前最新块信息,例如:

代码语言:javascript复制
curl -X POST --data '{
  "jsonrpc":"2.0",
  "method":"eth_blockNumber",
  "params":[],
  "id":83}' http://localhost:8545

在结果中可以获取当前最新一个区块编号:

代码语言:javascript复制
{
  "id":83,
  "jsonrpc": "2.0",
  "result": "0xd70adc" // 区块14093020
}

用区块链中最后一个区块的编号,减去交易所在区块编号,再加1,就可以得到一个以太坊交易的确认数了:

代码语言:javascript复制
交易确认数 = 最新区块号 - 交易所在区块号   1 = 15 - 11   1 = 5

2.2 使用golang获取以太坊交易确认数

基于上面的原理,我们很容易编写golang代码来获取以太坊交易确认数:

代码语言:javascript复制
// 定义一个方法,接收参数为交易哈希,返回参数为接口类型
func (eth *Http) getTxConfirms(hash string) (interface{}, error) {
 //获取交易确认高度
 // 判断交易哈希长度是否为66位
 if len(hash) != 66 {
  // 如果交易哈希长度不是66位,则返回交易哈希散列长度错误
  return nil, errors.New("GetTransactionReceipt hash length  wrong")
 }
 // 定义一个接口的变量,值为交易哈希
 args = []interface{}{hash}
 // 调用以太坊rpc,查询交易哈希
 params := NewHttpParams("eth_getTransactionReceipt", args)
 resBody, err := eth.rpc.HttpRequest(params)
 if err != nil {
  return nil, err
 }
 // 解析交易信息结果
 res, err := eth.ParseJsonRPCResponse(resBody)
 if err != nil {
  logger.Error("GetMatchBuyTxHashInfo", "step", "GetTransactionReceipt", "hash", hash, "err", err.Error())
  return nil, err
 }
 // 创建交易回执信息对象
 txReceipt := new(taskcommon.TxReceipt)
 resB, err := json.Marshal(res)
 if err != nil {
  logger.Error("GetMatchBuyTxHashInfo", "step", "Marshal res", "err", err.Error())
  return nil, err
 }
 if err := json.Unmarshal(resB, &txReceipt); err != nil {
  logger.Error("GetMatchBuyTxHashInfo", "step", "Unmarshal block", "err", err.Error())
  return nil, err
 }
 args = []interface{}{}
 blockParams := NewHttpParams("eth_blockNumber", args)
 blockResBody, err := eth.rpc.HttpRequest(blockParams)
 if err != nil {
  return "0x0", err
 }
 blockRes, err := eth.ParseJsonRPCResponse(blockResBody)
 if err != nil {
  return "0x0", err
 }
 latestnumber, _ := blockRes.(int)
 affirmNumber, _ := strconv.Atoi(txReceipt.BlockNumber)
 return latestnumber - affirmNumber   1, nil
}

调用上面实现的getTxConfirms()方法,就可以获取指定交易当前的确认数了:

代码语言:javascript复制
txConfirms := getTxConfirms(0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238)

注:以上将两个接口:eth_getTransactionReceipt 和 eth_blockNumber写在了同一方法内,代码不够简洁,可分别调用两个方法,获取值后再进行确认区块的运算


本系列文章:

从零开发区块链应用(一)--golang 配置文件管理工具 viper[2]

从零开发区块链应用(二)--mysql 安装及数据库表的安装创建[3]

从零开发区块链应用(三)--mysql 初始化及 gorm 框架使用[4]

从零开发区块链应用(四)--自定义业务错误信息[5]

从零开发区块链应用(五)--golang 网络请求[6]

从零开发区块链应用(六)--gin 框架使用[7]

从零开发区块链应用(七)--gin 框架参数获取[8]

从零开发区块链应用(八)--结构体初识[9]

从零开发区块链应用(九)--区块链结构体创建[10]

从零开发区块链应用(十)--golang 协程使用[11]

从零开发区块链应用(十一)--以太坊地址生成[12]

从零开发区块链应用(十二)--以太坊余额查询[13]

从零开发区块链应用(十三)--以太坊区块查询[14]

从零开发区块链应用(十四)--以太坊交易哈希查询[15]


参考资料

[1]

杰哥的技术杂货铺: https://learnblockchain.cn/people/3835

[2]

从零开发区块链应用(一)--golang配置文件管理工具viper: https://learnblockchain.cn/article/3446

[3]

从零开发区块链应用(二)--mysql安装及数据库表的安装创建: https://learnblockchain.cn/article/3447

[4]

从零开发区块链应用(三)--mysql初始化及gorm框架使用: https://learnblockchain.cn/article/3448

[5]

从零开发区块链应用(四)--自定义业务错误信息: https://learnblockchain.cn/article/3449

[6]

从零开发区块链应用(五)--golang网络请求: https://learnblockchain.cn/article/3457

[7]

从零开发区块链应用(六)--gin框架使用: https://learnblockchain.cn/article/3480

[8]

从零开发区块链应用(七)--gin框架参数获取: https://learnblockchain.cn/article/3481

[9]

从零开发区块链应用(八)--结构体初识: https://learnblockchain.cn/article/3482

[10]

从零开发区块链应用(九)--区块链结构体创建: https://learnblockchain.cn/article/3483

[11]

从零开发区块链应用(十)--golang协程使用: https://learnblockchain.cn/article/3484

[12]

从零开发区块链应用(十一)--以太坊地址生成: https://learnblockchain.cn/article/3485

[13]

从零开发区块链应用(十二)--以太坊余额查询: https://learnblockchain.cn/article/3498

[14]

从零开发区块链应用(十三)--以太坊区块查询: https://learnblockchain.cn/article/3499

[15]

从零开发区块链应用(十四)--以太坊交易哈希查询: https://learnblockchain.cn/article/3500

0 人点赞