TRON 私链
搭建独立的 TRON 私有测试网络,包括至少一个超级代表(SR)出块节点与一个普通全节点,并通过治理提议校准测试所需的链参数。
前置阅读
TRON 私链是 TRON 协议的完全隔离运行实例——拥有独立的创世区块、独立的超级代表(SR)集合以及专属的账本记录。私链的典型用途包括:端到端集成测试、智能合约上线前的预发布演练,以及需要在链上频繁执行操作但不想消耗主网真实 TRX 的开发场景。
最小规模的私链通常由一个出块 SR 全节点与至少一个普通同步全节点(负责同步区块、广播交易)组成。本文以双节点最小配置为例展开说明,若要扩展到包含多个超级代表的集群网络,只需沿用相同的配置模式即可。
准备工作
在开始部署前,请确保具备以下条件:
- 根据部署平台,安装 Oracle JDK 8(x86_64)或 17(ARM64)环境。
- 安装 Node.js 18 或更高版本与 npm,用于运行后文的 TronWeb 治理提议脚本。
- 准备至少两个 TRON 账户地址及其对应的私钥:一个用作超级代表账户,另一个或多个作为预充值的测试账户。可使用 TronWeb、命令行工具 wallet-cli 或 TronLink 钱包生成这些地址。
由于该私链完全隔离,创世区块中配置的超级代表地址将作为网络唯一的区块生产者,直到通过标准的超级代表选举流程选出更多 SR。
部署步骤
部署私链节点的基本流程与主网全节点一致,唯一的区别在于配置文件。两个节点运行相同的 FullNode.jar,仅在创世块定义、节点发现种子以及链上参数覆盖上有差异。
1. 创建部署目录
为超级代表(SR)和普通全节点分别创建独立的存放目录,以防数据库和配置文件冲突:
mkdir SR FullNode2. 将 FullNode.jar 放入对应目录
两个节点使用完全相同的 JAR 包。可根据部署节点中的指导自行编译或下载发布版:
cp FullNode.jar SR/
cp FullNode.jar FullNode/3. 将配置文件放入对应目录
从构建 FullNode.jar 所用的 java-tron release 标签或源码 commit 中取得 framework/src/main/resources/config.conf,复制到两个目录中并重命名。配置文件必须与 JAR 的源码版本一致;master 分支中的配置文件仅用于查看当前字段,不应直接用于其他版本的 JAR。
cp config.conf SR/supernode.conf
cp config.conf FullNode/fullnode.conf4. 编辑各配置文件
请分别修改两份配置文件中的以下关键参数项:
| 配置文件键名 | SR 节点(supernode.conf) | 普通全节点(fullnode.conf) | 修改原因 |
|---|---|---|---|
localwitness | SR 地址的私钥 | (保留为空列表) | SR 节点必须加载此私钥以对区块进行共识签名 |
genesis.block.witnesses | SR 地址 | 与 SR 相同 | 创世块的初始出块代表,两端配置必须一致 |
genesis.block.assets | 预充值账户及其初始 TRX 余额 | 与 SR 相同 | 创世块的初始资金分配,两端配置必须一致 |
node.p2p.version | 不与公共网络重复的自定义正整数 | 与 SR 相同 | 避免使用主网的 11111、Shasta 的 1 和 Nile 的 201910292;两端必须一致 |
seed.node.ip.list | 清空模板中的公共种子节点 | 仅保留 SR 节点的 IP:listen.port | 引导普通全节点连接并发现 SR 节点,避免私链节点尝试连接公共网络种子节点 |
block.needSyncCheck | false | true | 首个启动的出块节点需跳过同步检查,普通节点则需进行同步 |
node.discovery.enable | true | true | 启用节点发现,以便节点间能正常建立 P2P 握手连接 |
block.proposalExpireTime | 600000(10 分钟) | 与 SR 相同 | 缩短治理提议的过期时间以加快测试进度(主网默认值为 3 天) |
block.maintenanceTimeInterval | 300000(5 分钟) | 与 SR 相同 | 缩短维护周期以加快投票生效(主网默认值为 6 小时) |
committee.allowCreationOfContracts | 1 | 1 | 在私链启动时启用智能合约创建,并满足后续 TVM 功能参数的前置条件 |
committee.allowSameTokenName | 1 | 1 | 允许存在同名的 TRC-10 Token |
committee.allowTvmTransferTrc10 | 1 | 1 | 允许 TVM 转移 TRC-10 Token |
5. 单机部署时的端口调整
如果超级代表节点和普通全节点运行在同一台服务器上,为避免端口冲突,请为各自配置独立的端口:
listen.port:P2P 网络监听端口http端口组:HTTP RPC 端口rpc端口组:gRPC 端口
如果两个节点部署在不同的服务器上,可以直接使用配置文件中的默认端口。
6. 启动节点
打开两个终端,并在每个终端中进入包含 SR 和 FullNode 目录的部署根目录。
在第一个终端中启动 SR 节点:
cd SR
java -Xmx6g -XX:+HeapDumpOnOutOfMemoryError -jar FullNode.jar --witness -c supernode.conf在第二个终端中启动普通全节点:
cd FullNode
java -Xmx6g -XX:+HeapDumpOnOutOfMemoryError -jar FullNode.jar -c fullnode.conf启动几秒钟后,全节点日志中应能看到节点成功连接至 SR 节点并开始同步新产生的区块。
校准私链的关键链参数
全新启动的私链会采用初始默认参数,这与目标网络的实际运行环境(如 Energy 单价、出块奖励、智能合约执行上限、动态能量模型等)可能不同。为了让测试结果具有可比性,应以超级代表(SR)身份通过治理提议校准业务依赖的参数。
链参数会随治理和 java-tron 版本变化。提交前先通过目标网络的 wallet/getchainparameters 查询当前值,并在所用 java-tron 源码的 ProposalUtil.ProposalType 中确认参数编号和依赖关系。不要把本文示例当作永久有效的主网参数全集。
下面的两组参数是 2026-08-04 主网快照,适用于支持参数 #94 的 java-tron 4.8.1 及以上版本。修改分为两笔提议:第一笔先激活基础功能,待其到期并生效后,第二笔再设置依赖这些功能的参数。
先安装脚本所需的 TronWeb 依赖:
npm install tronweb@6脚本默认连接保留 HTTP 默认端口 8090 的 SR 节点。如果修改了 SR 节点的 HTTP 端口,请通过 PRIVATE_FULL_HOST 指定实际地址。
const { TronWeb } = require('tronweb');
const privateKey = process.env.TRON_PRIVATE_KEY;
if (!/^[0-9a-fA-F]{64}$/.test(privateKey || '')) {
throw new Error('Set TRON_PRIVATE_KEY to the 64-character hex private key of the SR');
}
const tronWeb = new TronWeb({
fullHost: process.env.PRIVATE_FULL_HOST || 'http://localhost:8090',
privateKey
});
// 治理提议 1 — 必须首先执行,以激活基础链参数和功能开关
const parametersForProposal1 = [
{ key: 11, value: 100 },
{ key: 19, value: 180000000000 }, { key: 16, value: 1 },
{ key: 20, value: 1 }, { key: 26, value: 1 },
{ key: 30, value: 1 }, { key: 5, value: 8000000 }, { key: 31, value: 128000000 },
{ key: 32, value: 1 }, { key: 39, value: 1 }, { key: 41, value: 1 },
{ key: 3, value: 1000 }, { key: 47, value: 10000000000 }, { key: 49, value: 1 },
{ key: 13, value: 80 }, { key: 7, value: 1000000 }, { key: 61, value: 600 },
{ key: 63, value: 1 }, { key: 65, value: 1 }, { key: 66, value: 1 },
{ key: 67, value: 1 }, { key: 68, value: 1000000 }, { key: 69, value: 1 },
{ key: 70, value: 14 }, { key: 71, value: 1 }, { key: 76, value: 1 }
];
// 治理提议 2 — 必须在治理提议 1 获批并到期生效后才能执行
const parametersForProposal2 = [
{ key: 47, value: 15000000000 }, { key: 59, value: 1 }, { key: 72, value: 1 },
{ key: 73, value: 5000000000 }, { key: 74, value: 2000 }, { key: 75, value: 34000 },
{ key: 77, value: 1 }, { key: 78, value: 864000 }, { key: 79, value: 1 },
{ key: 81, value: 1 }, { key: 82, value: 1000 }, { key: 83, value: 1 },
{ key: 87, value: 1 }, { key: 88, value: 1 }, { key: 89, value: 1 },
{ key: 94, value: 1 }
];
async function broadcast(unsignedTxn) {
const signedTxn = await tronWeb.trx.sign(unsignedTxn);
const result = await tronWeb.trx.sendRawTransaction(signedTxn);
if (!result.result || !result.txid) {
throw new Error(`Broadcast failed: ${JSON.stringify(result)}`);
}
return result.txid;
}
async function createProposal(parameters) {
const sorted = [...parameters].sort((a, b) => a.key - b.key);
const unsignedTxn = await tronWeb.transactionBuilder.createProposal(
sorted,
tronWeb.defaultAddress.base58
);
console.log('创建提议交易 txID:', await broadcast(unsignedTxn));
}
async function approveProposal(proposalID) {
const unsignedTxn = await tronWeb.transactionBuilder.voteProposal(
proposalID,
true,
tronWeb.defaultAddress.base58
);
console.log('批准提议交易 txID:', await broadcast(unsignedTxn));
}
async function main() {
const [action, argument] = process.argv.slice(2);
if (action === 'create' && (argument === '1' || argument === '2')) {
const parameters = argument === '1' ? parametersForProposal1 : parametersForProposal2;
await createProposal(parameters);
} else if (action === 'approve' && /^\d+$/.test(argument || '')) {
await approveProposal(Number(argument));
} else {
throw new Error('Usage: node proposal.js create <1|2> | approve <proposal_id>');
}
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});将脚本保存为 proposal.js。运行前,将 YOUR_SR_PRIVATE_KEY 替换为 SR 账户的 64 位十六进制私钥:
export TRON_PRIVATE_KEY="YOUR_SR_PRIVATE_KEY"
# 仅当 SR 节点未使用默认 HTTP 地址时设置:
# export PRIVATE_FULL_HOST="http://localhost:YOUR_SR_HTTP_PORT"然后按以下顺序处理每笔提议:
- 运行
node proposal.js create 1,记录输出的交易txID。 - 确认创建交易已经上链,再调用
wallet/listproposals查找该交易创建的实际proposal_id。不要假定它一定是1。 - 运行
node proposal.js approve <proposal_id>。多 SR 私链需要由足够多的当前活跃 SR 分别批准。 - 等待
expiration_time到期并确认状态为APPROVED,然后对第二组参数重复以上步骤,将创建命令改为node proposal.js create 2。
最后调用 wallet/getchainparameters 验证实际生效值。若目标不是主网,或使用的 java-tron 版本不同,应根据目标网络和对应版本源码调整参数集合。
完整的链上参数定义及各自的作用说明,请参阅网络参数。
相关资源
- 部署节点——节点的单机端到端部署流程
- 成为超级代表——超级代表的竞选与参选指南
- 超级代表 (SR) 最佳实践——生产环境超级代表节点的运维规范
- 网络参数——链上所有可通过治理提议修改的参数列表参考
- 资源模型:带宽与能量——TRON 的三类核心系统资源介绍
Updated 5 days ago