用 Trident 和 TronWeb 创建离线交易
前言
离线构造交易不仅为用户提供了在隔绝互联网环境下安全创建并签署交易的能力,有效规避了在线交易中私钥泄露、网络攻击等潜在风险,还赋予用户完全自主的交易控制权,摆脱对第三方服务的依赖。
本教程将以 TRX 转账为例,深入浅出地介绍离线构造交易的原理与实践,使用 Trident 和 TronWeb 分别展示如何在完全离线的状态下创建交易。
交易相关的 Protobuf 字段说明
交易主结构
message Transaction {
message raw {
repeated Contract contract = 1; // 具体交易:例如 TransferContract、VoteWitnessContract 类型等
int64 timestamp = 2; // 交易创建时间
int64 expiration = 3; // 过期时间
bytes ref_block_bytes = 4; // 参考区块高度的第6到8 (不包含)之间的字节
bytes ref_block_hash = 5; // 参考区块哈希第8到16(不包含)之间的字节
int64 fee_limit = 6; // 最大手续费限制
}
raw raw_data = 1; // 交易核心数据
repeated bytes signature = 2; // 签名列表
}区块相关字段说明
| 字段 | 说明 |
|---|---|
ref_block_bytes | 引用区块高度。取当前固化块高度的低2位字节(代码中的refBlockNum) |
expiration | 交易过期时间。须大于主网最新区块时间至少 1 到 3 个区块时间(3-9秒),不大于 24 小时 |
TRX 转账系统合约结构
message TransferContract {
bytes owner_address = 1; // 发送人地址
bytes to_address = 2; // 接收人地址
int64 amount = 3; // 转账金额(单位:SUN)
}用 Trident-java 构建离线交易
基于去中心化设计理念,Trident-java 在交易构建和签名环节原生支持离线操作模式。因此,可以直接调用其提供的相应方法来完成离线交易的构造。
准备开发环境
<dependency>
<groupId>org.tron.trident</groupId>
<artifactId>trident-core</artifactId>
<version>使用最新发布版本</version>
</dependency>初始化 ApiWrapper
String privateKey = "xxx";
ApiWrapper client = ApiWrapper.ofNile(privateKey); //根据需要,可选择主网(ofMainnet),Shasta测试网(ofShasta)或Nile测试网(ofNile)
// 如需使用自建节点,可以使用 ApiWrapper client = new ApiWrapper("grpc endpoint", "solidity grpc endpoint", "private_key");获取区块参数(可选)
在 Trident-java 中,可以通过以下方式设置为本地构建模式:
ApiWrapper.enableLocalCreate(blockId, expiration);再获取区块信息:
BlockExtention blockExtention = client.getNowBlockSolidity();
BlockId blockId = Utils.getBlockId(blockExtention);以上为手动获取区块信息的方法。如未开启本地构建模式,Trident 会自动向节点查询区块信息。
请注意,在 Trident 中,无论是否开启本地构建模式,创建交易及签名均为离线操作。因此,本设置为可选设置。本段仅用于帮助开发者理解交易结构。
构建交易
在 Trident-java 中,构造交易和签名均为离线操作,因此直接使用相应的交易方法即可。
TransactionExtention transaction = client.transfer(fromAddress, toAddress, 10); //转账金额单位是SUN。1TRX = 1,000,000 SUN
Transaction signTransaction = client.signTransaction(transaction);至此,离线交易就已经全部构建完成,须在设定的 expiration 之前广播。
用 TronWeb 构建离线交易
作为 TRON 官方推荐的 javascript sdk,TronWeb 也提供完整的离线交易方法,可以实现"私钥永不联网“的最高级安全标准。
准备开发环境
npm install tronweb初始化 TronWeb 实例
const TronWeb = require('tronweb');
const tronWeb = new TronWeb({
fullHost: fullnode或者fullhost参数,二选一即可 //此处不可为空,否则会初始化失败
privateKey: '你的私钥'
});
获取区块参数(此步骤需联网)
const latestBlock = await tronWeb.trx.getCurrentBlock();
const refBlockNum = latestBlock.block_header.raw_data.number.toString(16).slice(-4).padStart(4, '0');
const refBlockHash = latestBlock.blockID.substring(16, 32);参数示例
除联网获取的参数外,还需要获取当前的 timestamp。
{
"ref_block_num": 48732987,
"ref_block_hash": "a1b2c3d4e5f6",
"expiration": 1743594712000 //单位:毫秒
"timestamp": 1743591112000
}离线构造交易
此处地址均使用 Base58Check 格式,如原本是 hex 格式,则无需toHex方法。
function buildOfflineTransaction(
fromAddress,
toAddress,
amountInTRX,
refBlockParams
) {
// 构造交易对象
const transaction = tronWeb.transactionBuilder.sendTrx(
tronWeb.address.toHex(toAddress),
tronWeb.toSun(amountInTRX), // TRX转SUN
tronWeb.address.toHex(fromAddress),
refBlockParams // 区块参数
);
return transaction;
}离线签名
function signOfflineTransaction(transaction, privateKey) {
return tronWeb.trx.sign(transaction, privateKey {
useTronHeader: true, // 必须开启
});
}完整流程演示
const params = {
fromAddress: 'Base58CheckSender',
toAddress: 'Base58CheckReceiver',
amount: 888,
refBlockParams: {
ref_block_num: 48732987,
ref_block_hash: 'a1b2c3d4e5f6',
expiration: 1743594712000,
timestamp: 1743591112000
},
privateKey: '私钥'
};
const rawTx = buildOfflineTransaction(
params.fromAddress,
params.toAddress,
params.amount,
params.refBlockParams
);
const signedTx = signOfflineTransaction(rawTx, params.privateKey);相关 sdk 链接
Trident-java:https://github.com/tronprotocol/trident
TronWeb:https://github.com/tronprotocol/tronweb
Updated 9 months ago