跳到主要内容

交易查询方法

交易查询是区块链浏览器的核心功能之一,它允许用户查找和分析区块链上的交易记录。本章将详细介绍区块链交易查询的各种方法和技巧,包括通过交易ID、地址、区块等不同维度进行查询,以及如何处理交易状态和实现高级筛选功能。

交易ID查询

交易ID(Transaction ID,通常简称为txid或hash)是识别区块链上特定交易的唯一标识符。通过交易ID查询是最直接、最精确的交易查询方式。

交易ID的生成

交易ID通常是交易数据的加密哈希值,使用的哈希算法因区块链而异:

  • 比特币:使用SHA-256双哈希(SHA-256(SHA-256(交易数据)))
  • 以太坊:使用Keccak-256哈希

交易ID通常以十六进制字符串表示,例如:0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

通过交易ID查询交易详情

使用Web3.js或Ethers.js库可以轻松实现通过交易ID查询交易详情的功能:

// 使用Web3.js通过交易ID查询交易详情
async function getTransactionByHash(web3, transactionHash) {
try {
const transaction = await web3.eth.getTransaction(transactionHash);
if (!transaction) {
return { error: '交易不存在' };
}

// 获取交易收据(包含交易状态和Gas使用情况)
const receipt = await web3.eth.getTransactionReceipt(transactionHash);

// 组合交易数据和收据数据
return {
hash: transaction.hash,
blockHash: transaction.blockHash,
blockNumber: transaction.blockNumber,
from: transaction.from,
to: transaction.to,
value: web3.utils.fromWei(transaction.value, 'ether'),
gasPrice: web3.utils.fromWei(transaction.gasPrice, 'gwei'),
gas: transaction.gas,
gasUsed: receipt ? receipt.gasUsed : null,
cumulativeGasUsed: receipt ? receipt.cumulativeGasUsed : null,
status: receipt ? receipt.status : null, // 1表示成功,0表示失败
nonce: transaction.nonce,
input: transaction.input,
timestamp: transaction.blockNumber ? await getBlockTimestamp(web3, transaction.blockNumber) : null
};
} catch (error) {
console.error('查询交易失败:', error);
return { error: '查询交易失败' };
}
}

// 获取区块时间戳
async function getBlockTimestamp(web3, blockNumber) {
const block = await web3.eth.getBlock(blockNumber);
return block.timestamp;
}

// 使用示例
const Web3 = require('web3');
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID');

const transactionHash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
getTransactionByHash(web3, transactionHash)
.then(transaction => console.log(transaction))
.catch(error => console.error(error));

交易详情展示要点

在区块链浏览器中展示交易详情时,应包含以下关键信息:

  1. 基本信息:交易ID、区块号、时间戳、状态(成功/失败)
  2. 参与方:发送地址、接收地址
  3. 金额信息:转账金额、交易费用
  4. Gas信息:Gas价格、Gas用量、Gas上限
  5. 技术细节:nonce值、输入数据
  6. 相关链接:区块详情链接、发送地址详情链接、接收地址详情链接

地址交易查询

地址交易查询允许用户查看特定地址的所有交易历史,这对于跟踪资金流动和分析地址活动非常有用。

地址交易查询的实现方法

实现地址交易查询的方法主要有两种:

  1. 使用公共API:如Etherscan API、Blockchair API等
  2. 直接从节点查询:使用Web3.js或Ethers.js库从以太坊节点查询

下面是使用Etherscan API查询地址交易的示例:

// 使用Etherscan API查询地址交易
async function getAddressTransactions(address, apiKey, page = 1, offset = 10, sort = 'desc') {
try {
const url = `https://api.etherscan.io/api?module=account&action=txlist&address=${address}&startblock=0&endblock=99999999&page=${page}&offset=${offset}&sort=${sort}&apikey=${apiKey}`;

const response = await fetch(url);
const data = await response.json();

if (data.status === '0') {
return { error: data.message };
}

// 处理交易数据
const transactions = data.result.map(tx => ({
hash: tx.hash,
blockNumber: tx.blockNumber,
timestamp: new Date(tx.timeStamp * 1000).toISOString(),
from: tx.from,
to: tx.to,
value: ethers.utils.formatEther(tx.value),
gasPrice: ethers.utils.formatUnits(tx.gasPrice, 'gwei'),
gasUsed: tx.gasUsed,
isError: tx.isError === '1',
txreceipt_status: tx.txreceipt_status,
input: tx.input
}));

return { transactions, total: data.result.length };
} catch (error) {
console.error('查询地址交易失败:', error);
return { error: '查询地址交易失败' };
}
}

// 使用示例
const ethers = require('ethers');
const address = '0x1234567890abcdef1234567890abcdef12345678';
const apiKey = 'YOUR_ETHERSCAN_API_KEY';

getAddressTransactions(address, apiKey)
.then(result => console.log(result))
.catch(error => console.error(error));

地址交易查询的优化策略

查询大量地址交易可能会遇到性能瓶颈,以下是一些优化策略:

  1. 分页加载:限制每页返回的交易数量,支持分页浏览
  2. 时间范围筛选:允许用户指定交易查询的时间范围
  3. 交易类型筛选:区分发送交易和接收交易
  4. 金额范围筛选:允许用户按交易金额进行筛选
  5. 本地缓存:缓存热门地址的交易数据,减少API调用

区块交易查询

区块交易查询允许用户查看特定区块中包含的所有交易,这对于分析区块内容和网络活动非常有用。

通过区块号查询交易

// 使用Web3.js通过区块号查询交易
async function getBlockTransactions(web3, blockNumber, includeDetails = false) {
try {
const block = await web3.eth.getBlock(blockNumber, includeDetails);
if (!block) {
return { error: '区块不存在' };
}

// 如果includeDetails为true,block.transactions包含完整交易详情
if (includeDetails) {
return {
blockNumber: block.number,
timestamp: block.timestamp,
transactionCount: block.transactions.length,
transactions: block.transactions.map(tx => ({
hash: tx.hash,
from: tx.from,
to: tx.to,
value: web3.utils.fromWei(tx.value, 'ether'),
gasPrice: web3.utils.fromWei(tx.gasPrice, 'gwei')
}))
};
}

// 否则,block.transactions只包含交易哈希,需要单独查询每个交易
const transactions = [];
for (const txHash of block.transactions) {
try {
const tx = await web3.eth.getTransaction(txHash);
if (tx) {
transactions.push({
hash: tx.hash,
from: tx.from,
to: tx.to,
value: web3.utils.fromWei(tx.value, 'ether'),
gasPrice: web3.utils.fromWei(tx.gasPrice, 'gwei')
});
}
} catch (error) {
console.error(`查询交易 ${txHash} 失败:`, error);
}
}

return {
blockNumber: block.number,
timestamp: block.timestamp,
transactionCount: block.transactions.length,
transactions
};
} catch (error) {
console.error('查询区块交易失败:', error);
return { error: '查询区块交易失败' };
}
}

// 使用示例
const Web3 = require('web3');
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID');
const blockNumber = 12345678;

getBlockTransactions(web3, blockNumber, true)
.then(result => console.log(result))
.catch(error => console.error(error));

区块交易的批量处理

对于包含大量交易的区块,批量处理可以提高查询效率:

// 批量查询区块交易
async function batchGetBlockTransactions(web3, blockNumber, batchSize = 10) {
try {
const block = await web3.eth.getBlock(blockNumber);
if (!block) {
return { error: '区块不存在' };
}

const transactionHashes = block.transactions;
const transactions = [];

// 分批次查询交易
for (let i = 0; i < transactionHashes.length; i += batchSize) {
const batch = transactionHashes.slice(i, i + batchSize);
const batchPromises = batch.map(txHash =>
web3.eth.getTransaction(txHash).catch(error => {
console.error(`查询交易 ${txHash} 失败:`, error);
return null;
})
);

const batchResults = await Promise.all(batchPromises);
const validTransactions = batchResults.filter(tx => tx !== null);
transactions.push(...validTransactions);

// 避免请求过于频繁
if (i + batchSize < transactionHashes.length) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}

return {
blockNumber: block.number,
timestamp: block.timestamp,
transactionCount: block.transactions.length,
transactions: transactions.map(tx => ({
hash: tx.hash,
from: tx.from,
to: tx.to,
value: web3.utils.fromWei(tx.value, 'ether'),
gasPrice: web3.utils.fromWei(tx.gasPrice, 'gwei')
}))
};
} catch (error) {
console.error('批量查询区块交易失败:', error);
return { error: '批量查询区块交易失败' };
}
}

交易状态查询

交易状态查询用于确定交易是否已确认、确认次数以及是否成功执行。这对于监控交易进度和故障排查非常重要。

交易状态的主要指标

  1. 是否已入块:交易是否已被矿工打包进区块
  2. 确认次数:交易所在区块之后又新增了多少个区块
  3. 执行状态:交易是否成功执行(仅适用于支持智能合约的区块链)
  4. Gas使用情况:交易实际消耗的Gas量
// 查询交易状态
async function getTransactionStatus(web3, transactionHash) {
try {
const transaction = await web3.eth.getTransaction(transactionHash);
if (!transaction) {
return { status: 'notFound', message: '交易不存在' };
}

// 检查交易是否已入块
if (!transaction.blockNumber) {
return {
status: 'pending',
message: '交易待确认',
from: transaction.from,
to: transaction.to,
value: web3.utils.fromWei(transaction.value, 'ether')
};
}

// 获取交易收据
const receipt = await web3.eth.getTransactionReceipt(transactionHash);
if (!receipt) {
return {
status: 'processing',
message: '交易处理中',
blockNumber: transaction.blockNumber
};
}

// 获取最新区块号,计算确认次数
const latestBlock = await web3.eth.getBlockNumber();
const confirmations = latestBlock - transaction.blockNumber;

return {
status: receipt.status ? 'success' : 'failed',
message: receipt.status ? '交易成功' : '交易失败',
blockNumber: transaction.blockNumber,
confirmations: confirmations,
gasUsed: receipt.gasUsed,
cumulativeGasUsed: receipt.cumulativeGasUsed,
from: transaction.from,
to: transaction.to,
value: web3.utils.fromWei(transaction.value, 'ether')
};
} catch (error) {
console.error('查询交易状态失败:', error);
return { status: 'error', message: '查询交易状态失败' };
}
}

// 使用示例
const transactionHash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
getTransactionStatus(web3, transactionHash)
.then(status => console.log(status))
.catch(error => console.error(error));

交易状态的实时监控

对于重要交易,可能需要实时监控其状态变化:

// 实时监控交易状态
function monitorTransactionStatus(web3, transactionHash, callback, interval = 5000, maxAttempts = 60) {
let attempts = 0;

const checkStatus = async () => {
attempts++;

try {
const status = await getTransactionStatus(web3, transactionHash);
callback(status);

// 如果交易已确认或达到最大尝试次数,停止监控
if (status.status === 'success' || status.status === 'failed' || status.status === 'notFound' || attempts >= maxAttempts) {
return;
}

// 否则继续监控
setTimeout(checkStatus, interval);
} catch (error) {
console.error('监控交易状态出错:', error);
callback({ status: 'error', message: '监控交易状态出错' });

// 出错后继续尝试监控
if (attempts < maxAttempts) {
setTimeout(checkStatus, interval);
}
}
};

// 开始监控
checkStatus();
}

// 使用示例
const transactionHash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';

monitorTransactionStatus(web3, transactionHash, (status) => {
console.log('交易状态更新:', status);

if (status.status === 'success') {
console.log(`交易已确认,确认次数: ${status.confirmations}`);
} else if (status.status === 'failed') {
console.log('交易执行失败');
} else if (status.status === 'pending') {
console.log('交易等待确认中...');
}
});

高级筛选

高级筛选功能允许用户根据多个条件组合查询交易,这对于复杂的交易分析非常有用。

常见的筛选条件

  1. 时间范围:交易发生的时间段
  2. 金额范围:交易金额的区间
  3. 交易类型:普通转账、合约创建、合约调用等
  4. Gas价格范围:交易的Gas价格区间
  5. 状态:成功、失败、待确认等
  6. 输入数据模式:合约调用的特定函数或参数

高级筛选的实现

// 高级交易筛选示例
class TransactionFilter {
constructor() {
this.filters = {};
}

// 设置时间范围筛选
setTimeRange(fromTimestamp, toTimestamp) {
this.filters.timeRange = { from: fromTimestamp, to: toTimestamp };
return this;
}

// 设置金额范围筛选
setValueRange(minValue, maxValue, unit = 'ether') {
this.filters.valueRange = { min: minValue, max: maxValue, unit };
return this;
}

// 设置交易类型筛选
setTransactionType(type) {
this.filters.transactionType = type;
return this;
}

// 设置Gas价格范围筛选
setGasPriceRange(minGasPrice, maxGasPrice, unit = 'gwei') {
this.filters.gasPriceRange = { min: minGasPrice, max: maxGasPrice, unit };
return this;
}

// 设置交易状态筛选
setStatus(status) {
this.filters.status = status;
return this;
}

// 应用筛选条件到交易列表
applyToTransactions(transactions, web3) {
return transactions.filter(tx => this.matchesFilter(tx, web3));
}

// 检查单个交易是否匹配筛选条件
matchesFilter(tx, web3) {
// 检查时间范围
if (this.filters.timeRange) {
if (tx.timestamp < this.filters.timeRange.from || tx.timestamp > this.filters.timeRange.to) {
return false;
}
}

// 检查金额范围
if (this.filters.valueRange) {
const txValue = parseFloat(web3.utils.fromWei(tx.value, this.filters.valueRange.unit));
if (txValue < this.filters.valueRange.min || txValue > this.filters.valueRange.max) {
return false;
}
}

// 检查交易类型
if (this.filters.transactionType) {
if (this.filters.transactionType === 'contract_creation' && tx.to !== null) {
return false;
}
if (this.filters.transactionType === 'normal_transfer' && (tx.to === null || tx.input !== '0x')) {
return false;
}
if (this.filters.transactionType === 'contract_interaction' && (tx.to === null || tx.input === '0x')) {
return false;
}
}

// 检查Gas价格范围
if (this.filters.gasPriceRange) {
const txGasPrice = parseFloat(web3.utils.fromWei(tx.gasPrice, this.filters.gasPriceRange.unit));
if (txGasPrice < this.filters.gasPriceRange.min || txGasPrice > this.filters.gasPriceRange.max) {
return false;
}
}

// 检查交易状态
if (this.filters.status && tx.status !== undefined) {
if (this.filters.status === 'success' && tx.status !== true) {
return false;
}
if (this.filters.status === 'failed' && tx.status !== false) {
return false;
}
}

return true;
}
}

// 使用示例
const filter = new TransactionFilter();
filter
.setTimeRange(Date.now() - 7 * 24 * 60 * 60 * 1000, Date.now()) // 过去7天
.setValueRange(0.1, 10) // 0.1到10 ETH
.setGasPriceRange(10, 50) // 10到50 Gwei
.setStatus('success'); // 仅成功交易

// 假设我们有一个交易列表
const transactions = [/* 交易数据数组 */];
const filteredTransactions = filter.applyToTransactions(transactions, web3);
console.log('筛选后的交易数量:', filteredTransactions.length);

交易查询的性能优化

随着区块链数据量的不断增长,交易查询的性能优化变得越来越重要。以下是一些常见的优化策略:

  1. 使用索引数据库:建立专门的索引数据库存储交易数据,提高查询速度
  2. 缓存热点数据:缓存频繁查询的交易数据,减少数据库访问
  3. 异步加载:使用异步加载技术,在用户滚动时动态加载更多交易
  4. 预加载相关数据:在显示交易详情时,预加载相关的区块和地址数据
  5. 数据压缩:对交易数据进行压缩存储,减少存储空间和传输量
  6. 查询优化:优化SQL查询语句,使用合适的索引

总结

交易查询是区块链浏览器的核心功能,本章介绍了通过交易ID、地址、区块等不同维度查询交易的方法,以及如何处理交易状态和实现高级筛选功能。通过掌握这些技术,你将能够构建高效、功能完善的交易查询系统,为用户提供良好的区块链数据浏览体验。在实际开发中,还需要根据具体的区块链平台和用户需求,不断优化查询性能和用户体验。