Develop blockchain applications from scratch (15)--Ethereum transaction matching query

1. Obtain intra-block transactions

1.1 Get transaction details in the latest block

Get the latest block and put it in the variable num

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

Get the block information of the block and put it in the variable res

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

To define new objects, the block structure of Ethereum has been explained in "Developing Blockchain Applications from Scratch (9)"

block := new(taskcommon.Block)

Serialize the resB variable containing the block information, determine whether there is an error in the serial number, and determine whether there is an error in the deserialization of the resB variable

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
}

Delay function to execute after this method finishes

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

Get the queried block height

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

Returns transaction information in the block, block height, error information

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

full code

// 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 Get the transaction details in the specified block

Obtaining the transaction details of the specified block is the same as the above method, the difference is that the specified block needs to have a block height parameter, so the code will not be repeated here.

// 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
}

2. Obtain the main information of the matching transaction receipt

Query the transaction receipt information of a transaction

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

To define new objects, the Ethereum transaction structure has been explained in "Developing Blockchain Applications from Scratch (9)"

txReceipt := new(taskcommon.TxReceipt)

Serialize the resB variable containing the block information, determine whether there is an error in the serial number, and determine whether there is an error in the deserialization of the resB variable

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
}

Each transaction has a receipt that contains the result of executing the transaction, such as any return values ​​and logs, and an event result status of "1" (success) or "0" (failure).

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

Define hash hash and from address variables

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

The following are some business codes snapped up by nft, which are ignored here

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
	}
}

full code

// 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")
}

3. Obtain the number of transactions in the block

One way to iterate through a transaction without acquiring a block is to call the client's TransactionInBlock method. This method only accepts block hashes and index values ​​for intra-block transactions. TransactionCount can be called to find out how many transactions are in the block.

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
}

Guess you like

Origin blog.csdn.net/cljdsc/article/details/122748778