1

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

 2 years ago
source link: https://learnblockchain.cn/article/3503
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、获取区块内交易

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
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK