从零开发区块链应用(十五)--以太坊交易匹配查询

获取区块内交易

一、获取区块内交易

1.1 获取最新区块中的交易详情

获取最新区块,放到变量num中

num, err := rc.Client.GetLatestBlockNumber()

获取区块的区块信息,放到变量res中

res, err := rc.Client.GetBlockByNumber(num, true)
if err != nil {
    logger.Error("GetBlockMatchTx", "step", "GetBlockByNumber", "err", err.Error())
    return BlockInfo{}, 0, err
}

定义新的对象,以太坊block结构体已在《从零开发区块链应用(九)》中讲解

block := new(taskcommon.Block)

序列化包含区块信息的resB变量,判断序列号是否出现错误,判断反序列化resB变量是否出现错误

resB, err := json.Marshal(res)
if err != nil {
    logger.Error("GetBlockMatchTx", "step", "Marshal res", "err", err.Error())
    return BlockInfo{}, 0, err
}
if err := json.Unmarshal(resB, &block); err != nil {
    logger.Error("GetBlockMatchTx", "step", "Unmarshal block", "err", err.Error())
    return BlockInfo{}, 0, err
}

延迟函数,在此方法结束后进行执行

defer func() {
    if r := recover(); r != nil {
        //fmt.Printf("捕获到的错误:%s\n", r)
        logger.Error("GetBlockMatchTx", "step", "block info", "panic blockNumber", num, "err", r)
    }
}()

获取所查询的区块高度

bnum, _ := common.HexToInt64(block.Number)

返回区块内交易信息,区块高度,错误信息

return BlockInfo{TxDatas: block.TxDatas}, bnum, nil

完整代码

// GetLastBlockTx 获取区块内匹配的交易
func (rc *RequestChain) GetLastBlockTx() (BlockInfo, int64, error) {

    num, err := rc.Client.GetLatestBlockNumber()
    res, err := rc.Client.GetBlockByNumber(num, true)
    if err != nil {
        logger.Error("GetBlockMatchTx", "step", "GetBlockByNumber", "err", err.Error())
        return BlockInfo{}, 0, err
    }
    block := new(taskcommon.Block)
    resB, err := json.Marshal(res)
    if err != nil {
        logger.Error("GetBlockMatchTx", "step", "Marshal res", "err", err.Error())
        return BlockInfo{}, 0, err
    }
    if err := json.Unmarshal(resB, &block); err != nil {
        logger.Error("GetBlockMatchTx", "step", "Unmarshal block", "err", err.Error())
        return BlockInfo{}, 0, err
    }
    defer func() {
        if r := recover(); r != nil {
            //fmt.Printf("捕获到的错误:%s\n", r)
            logger.Error("GetBlockMatchTx", "step", "block info", "panic blockNumber", num, "err", r)
        }
    }()
    bnum, _ := common.HexToInt64(block.Number)
    return BlockInfo{TxDatas: block.TxDatas}, bnum, nil
}

1.2 获取指定区块中的交易详情

获取指定区块交易详情与上面的方法是一样的,区别在于需要指定区块需要有一个区块高度的传参,所以此处不再对代码进行赘述

// GetBlockMatchTx 获取区块内匹配的交易
func (rc *RequestChain) GetBlockMatchTx(blockNumber string) (BlockInfo, error) {
    res, err := rc.Client.GetBlockByNumber(blockNumber, true)
    if err != nil {
        logger.Error("GetBlockMatchTx", "step", "GetBlockByNumber", "err", err.Error())
        return BlockInfo{}, err
    }
    block := new(taskcommon.Block)
    resB, err := json.Marshal(res)
    if err != nil {
        logger.Error("GetBlockMatchTx", "step", "Marshal res", "err", err.Error())
        return BlockInfo{}, err
    }
    if err := json.Unmarshal(resB, &block); err != nil {
        logger.Error("GetBlockMatchTx", "step", "Unmarshal block", "err", err.Error())
        return BlockInfo{}, err
    }
    defer func() {
        if r := recover(); r != nil {
            //fmt.Printf("捕获到的错误:%s\n", r)
            logger.Error("GetBlockMatchTx", "step", "block info", "panic blockNumber", blockNumber)
        }
    }()

    return BlockInfo{TxDatas: block.TxDatas}, nil
}

二、 获取匹配交易回执主要信息

查询某个交易的交易回执信息

// 分析回执
res, err := rc.Client.GetTransactionReceipt(hash)
if err != nil {
    logger.Error("GetMatchBuyTxHashInfo", "step", "GetTransactionReceipt", "hash", hash, "err", err.Error())
    return TransferReceiptInfo{}, err
}

定义新的对象,以太坊transaction结构体已在《从零开发区块链应用(九)》中讲解

txReceipt := new(taskcommon.TxReceipt)

序列化包含区块信息的resB变量,判断序列号是否出现错误,判断反序列化resB变量是否出现错误

resB, err := json.Marshal(res)
if err != nil {
    logger.Error("GetMatchBuyTxHashInfo", "step", "Marshal res", "err", err.Error())
    return TransferReceiptInfo{}, err
}
if err := json.Unmarshal(resB, &txReceipt); err != nil {
    logger.Error("GetMatchBuyTxHashInfo", "step", "Unmarshal block", "err", err.Error())
    return TransferReceiptInfo{}, err
}

每个事务都有一个收据,其中包含执行事务的结果,例如任何返回值和日志,以及为“1”(成功)或“0”(失败)的事件结果状态。

if txReceipt.Status != "0x1" {
        return TransferReceiptInfo{}, errors.New("contract vm running false")
    }

定义散列哈希及from地址变量

matchTopic := "0x6656db943f28baede9b164738dc5fa235b9da60d5c20a38b0eb0230c21196254"
matchAddr := "0x6e60F5243e1a3F0Be3F407b5AFE9e5395ee82aa2"

以下为nft抢购的部分业务代码,此处忽略

for _, value := range txReceipt.Logs {
    if value.Address != matchAddr {
        continue
    }
    if strings.ToLower(value.Topics[0]) == matchTopic && len(value.Topics) == 4 {
        var record TransferReceiptInfo
        record.OrderId = value.Topics[2][2:]
        record.NftContract = value.Topics[3]
        if len(clearZero(value.Data[2:66])) == 0 {
            record.NftId = "0"
        } else {
            record.NftId = clearZero(value.Data[2:66])
        }
        record.NftNums = clearZero(value.Data[66:130])
        record.NftAmount = clearZero(value.Data[194:258])
        // 计算nft 单价
        nftAmount, _ := new(big.Int).SetString(record.NftAmount, 16)
        nftNums, _ := new(big.Int).SetString(record.NftNums, 16)
        record.UnitPrice = clearZero(hex.EncodeToString(new(big.Int).Div(nftAmount, nftNums).Bytes()))
        return record, nil
    }
}

完整代码

// GetMatchReceiptInfo 获取匹配交易回执主要信息
func (rc *RequestChain) GetMatchReceiptInfo(hash string) (TransferReceiptInfo, error) {
    defer func() {
        if r := recover(); r != nil {
            //fmt.Printf("%s 捕获到的错误:%s\n", hash,r)
            //logger.Error("GetMatchReceiptInfo", "setp", "txReceipt info", "panic hash", hash)
        }
    }()

    // 分析回执
    res, err := rc.Client.GetTransactionReceipt(hash)
    if err != nil {
        logger.Error("GetMatchBuyTxHashInfo", "step", "GetTransactionReceipt", "hash", hash, "err", err.Error())
        return TransferReceiptInfo{}, err
    }
    txReceipt := new(taskcommon.TxReceipt)
    resB, err := json.Marshal(res)
    if err != nil {
        logger.Error("GetMatchBuyTxHashInfo", "step", "Marshal res", "err", err.Error())
        return TransferReceiptInfo{}, err
    }
    if err := json.Unmarshal(resB, &txReceipt); err != nil {
        logger.Error("GetMatchBuyTxHashInfo", "step", "Unmarshal block", "err", err.Error())
        return TransferReceiptInfo{}, err
    }

    if txReceipt.Status != "0x1" {
        return TransferReceiptInfo{}, errors.New("contract vm running false")
    }
    matchTopic := "0x6656db943f28baede9b164738dc5fa235b9da60d5c20a38b0eb0230c21196254"
    matchAddr := "0x7b4452dd6c38597fa9364ac8905c27ea44425832"
    for _, value := range txReceipt.Logs {
        if value.Address != matchAddr {
            continue
        }
        if strings.ToLower(value.Topics[0]) == matchTopic && len(value.Topics) == 4 {
            var record TransferReceiptInfo
            record.OrderId = value.Topics[2][2:]
            record.NftContract = value.Topics[3]
            if len(clearZero(value.Data[2:66])) == 0 {
                record.NftId = "0"
            } else {
                record.NftId = clearZero(value.Data[2:66])
            }
            record.NftNums = clearZero(value.Data[66:130])
            record.NftAmount = clearZero(value.Data[194:258])
            // 计算nft 单价
            nftAmount, _ := new(big.Int).SetString(record.NftAmount, 16)
            nftNums, _ := new(big.Int).SetString(record.NftNums, 16)
            record.UnitPrice = clearZero(hex.EncodeToString(new(big.Int).Div(nftAmount, nftNums).Bytes()))
            return record, nil
        }
    }
    return TransferReceiptInfo{}, errors.New("no record")
}

三、获取区块内交易数量

在不获取块的情况下遍历事务的一种方法是调用客户端的TransactionInBlock方法。 此方法仅接受块哈希和块内事务的索引值。 可以调用TransactionCount来了解块中有多少个事务。

blockHash := common.HexToHash("0x9e8751ebb5069389b855bba72d94902cc385042661498a415979b7b6ee9ba4b9")
count, err := client.TransactionCount(context.Background(), blockHash)
if err != nil {
  log.Fatal(err)
}

for idx := uint(0); idx < count; idx++ {
  tx, err := client.TransactionInBlock(context.Background(), blockHash, idx)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(tx.Hash().Hex()) // 0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2
}

本系列文章: 从零开发区块链应用(一)--golang配置文件管理工具viper 从零开发区块链应用(二)--mysql安装及数据库表的安装创建 从零开发区块链应用(三)--mysql初始化及gorm框架使用 从零开发区块链应用(四)--自定义业务错误信息 从零开发区块链应用(五)--golang网络请求 从零开发区块链应用(六)--gin框架使用 从零开发区块链应用(七)--gin框架参数获取 从零开发区块链应用(八)--结构体初识 从零开发区块链应用(九)--区块链结构体创建 从零开发区块链应用(十)--golang协程使用 从零开发区块链应用(十一)--以太坊地址生成 从零开发区块链应用(十二)--以太坊余额查询 从零开发区块链应用(十三)--以太坊区块查询 从零开发区块链应用(十四)--以太坊交易哈希查询 从零开发区块链应用(十五)--以太坊交易匹配查询 从零开发区块链应用(十六)--ETH转账处理


点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
杰哥的技术杂货铺
杰哥的技术杂货铺
0x6e60...2aa2
六年区块链开发及运维经验,成都电子科技大学Web3讲师,利用该平台进行技术分享,可私信进行交流沟通