账户权限管理
TRON 账户如何通过权限、权重和签名阈值实现多方共管。
TRON 账户不必只由一个私钥控制。通过账户权限管理(TIP-16),一个账户可以把控制权拆分给多个地址:每个地址配置一个权重,交易只有在有效签名权重之和达到阈值后才会通过校验。
这套机制通常用于金库、多方运营账户、SR 节点运维和企业热/冷密钥分离。Owner 权限负责最高控制权,Active 权限负责日常操作范围,Witness 权限仅服务于 SR 出块签名。
前置阅读
权限类型
每个 TRON 账户都围绕三类权限工作:
| 权限 | 用途 | 关键约束 |
|---|---|---|
| Owner | 账户最高控制权,可执行任意系统合约,也可修改账户权限结构 | 新账户默认只有 Owner 权限 |
| Witness | SR 账户用于区块生产签名 | 必须且只能包含 1 个密钥;不能授权普通交易 |
| Active | 面向日常操作的自定义权限,可限制允许执行的合约类型 | 每个账户最多 8 个 Active 权限 |
witness_permission 是协议和 API 中的字段名,因此本文在讨论权限类型时保留 Witness。当讨论区块生产角色时,仍使用超级代表(SR)。
阈值与权重
一个权限由阈值和密钥列表组成:
- 阈值:交易要获得该权限授权,签名权重总和必须达到或超过这个值。
- 密钥列表:每个条目包含一个 TRON 地址和一个正数权重。
节点校验交易时,会从交易签名中恢复出签名地址,在目标权限的 keys 列表中查找这些地址,并累加对应权重。达到阈值,交易才会继续执行;达不到阈值,交易会被拒绝。
权限配置必须满足以下边界:
| 规则 | 要求 |
|---|---|
| 单个权限的密钥数 | 不得超过 TotalSignNum(协议硬编码上限,主网为 5,无法通过提案修改) |
| 地址唯一性 | 同一权限的 keys 列表不能出现重复地址 |
| 权重 | 每个 weight 必须大于 0 |
| 权重总和 | 所有密钥权重之和必须大于或等于阈值 |
permission_name | 最多 32 字节 |
parent_id | 必须为 0 |
| Witness 权限 | 必须且只能有 1 个密钥 |
默认单签账户
新账户默认是单签 Owner 权限:
threshold: 1
keys:
- address: <账户自身地址>, weight: 1账户私钥签名后贡献权重 1,正好达到阈值 1。
2-of-3 多方共管
典型的三方共管可以这样配置:
threshold: 2
keys:
- address: TKey1...AA, weight: 1
- address: TKey2...BB, weight: 1
- address: TKey3...CC, weight: 1三方中任意两方签名即可达到阈值。任意一方单独签名不会通过校验。
加权控制
不同参与方也可以拥有不同权重:
threshold: 3
keys:
- address: TFounder...A, weight: 2
- address: TCofnd1...B, weight: 1
- address: TCofnd2...C, weight: 1创始人加任意一位联合创始人即可达到阈值 3;两位联合创始人单独合作只有权重 2,不能授权交易。
Active 权限与合约类型限制
Active 权限不仅能做多签,还能限制“这个权限可以执行哪些系统合约”。限制由 operations 字段表达。
operations 是一个 32 字节(256 位)的小端位图。每一位对应 Transaction.Contract.ContractType 枚举中的一个合约类型 ID:
- ID
0对应第 0 个字节的第 0 位。 - ID
7对应第 0 个字节的第 7 位。 - ID
8对应第 1 个字节的第 0 位。 - ID
59对应第 7 个字节的第 3 位。
某一位为 1,表示该 Active 权限可以执行对应合约类型;为 0,表示禁止执行。
常用系统合约类型 ID
| ID | ContractType | 功能 |
|---|---|---|
| 0 | AccountCreateContract | 创建账户 |
| 1 | TransferContract | 转账 TRX |
| 2 | TransferAssetContract | 转账 TRC-10 Token |
| 4 | VoteWitnessContract | 为超级代表候选人投票 |
| 5 | WitnessCreateContract | 申请成为 SR 候选人 |
| 11 | FreezeBalanceContract | Stake 1.0 质押 TRX |
| 12 | UnfreezeBalanceContract | Stake 1.0 解除质押 TRX |
| 13 | WithdrawBalanceContract | 提取投票奖励 |
| 16 | ProposalCreateContract | 创建治理提案 |
| 17 | ProposalApproveContract | 批准治理提案 |
| 30 | CreateSmartContract | 部署智能合约 |
| 31 | TriggerSmartContract | 调用智能合约 |
| 33 | UpdateSettingContract | 更新合约调用方资源分摊比例 |
| 45 | UpdateEnergyLimitContract | 调整合约部署方能量代付上限 |
| 46 | AccountPermissionUpdateContract | 更新账户权限 |
| 48 | ClearABIContract | 清除合约 ABI |
| 49 | UpdateBrokerageContract | 更新 SR 分成比例(Brokerage) |
| 54 | FreezeBalanceV2Contract | Stake 2.0 质押 TRX |
| 55 | UnfreezeBalanceV2Contract | Stake 2.0 发起解除质押 |
| 56 | WithdrawExpireUnfreezeContract | 提取到期的已解除质押 TRX |
| 57 | DelegateResourceContract | 代理带宽或能量 |
| 58 | UnDelegateResourceContract | 撤销资源代理 |
| 59 | CancelAllUnfreezeV2Contract | 取消所有待处理的解除质押 |
完整枚举参见系统合约类型详情。
位图计算示例
如果一个 Active 权限只允许 TRX 转账(ID 1)、SR 投票(ID 4)和 Stake 2.0 质押(ID 54),需要把第 1、4、54 位设为 1:
import org.bouncycastle.util.encoders.Hex;
int[] contractIds = { 1, 4, 54 };
byte[] operations = new byte[32];
for (int id : contractIds) {
operations[id / 8] |= (byte) (1 << (id % 8));
}
System.out.println(Hex.toHexString(operations));
// 1200000000004000000000000000000000000000000000000000000000000000反向解码时,也按“字节序号 * 8 + 位序号”得到合约类型 ID:
public static List<Integer> decodeOperations(String operationsHex) {
byte[] ops = Hex.decode(operationsHex);
List<Integer> ids = new ArrayList<>();
for (int i = 0; i < ops.length; i++) {
for (int bit = 0; bit < 8; bit++) {
if (((ops[i] >> bit) & 0x1) == 1) {
ids.add(i * 8 + bit);
}
}
}
return ids;
}| 允许执行的合约类型 | 十六进制开头 | 说明 |
|---|---|---|
TransferContract + VoteWitnessContract | 120000... | 设置 ID 1 和 ID 4 |
TransferContract + UpdateAssetContract | 028000... | 设置 ID 1 和 ID 15 |
| 主网默认全量系统合约 | 7fff1f... | 允许常见系统合约类型 |
读取位图时,以单字节为单位展开为二进制,最低有效位对应当前字节范围内最小的合约 ID。
业务模式:只允许转账的热密钥
一个金库账户可以把 Owner 权限交给冷钱包多签组,同时创建一个只允许 TransferContract 的 Active 权限。这个 Active 权限可以配置为:
threshold: 1- 一个日常运营热密钥,
weight: 1 operations只开放TransferContract(ID 1)
这样,运营热密钥可以支付日常 TRX 款项,但不能质押、投票、部署合约、修改权限,也不能转移账户最高控制权。Owner 多签继续留在冷环境中。
更新权限结构
修改账户权限需要提交 AccountPermissionUpdateContract。这个系统合约采用全量覆盖语义:即使只想改一个 Active 权限,也必须把 Owner、Witness 和完整 Active 列表一起提交。
message AccountPermissionUpdateContract {
bytes owner_address = 1;
Permission owner = 2;
Permission witness = 3;
repeated Permission actives = 4;
}| 字段 | 说明 |
|---|---|
owner_address | 要更新权限的账户地址 |
owner | 新的 Owner 权限,必填 |
witness | 新的 Witness 权限;普通非 SR 账户通常传 null |
actives | 新的 Active 权限列表,最多 8 个 |
权限更新交易本身必须由账户当前生效的 Owner 权限授权。
交易中的 Permission_id
Permission_id普通交易在合约体里通过 Permission_id 声明签名校验使用的权限:
Permission_id | 含义 |
|---|---|
0 | Owner 权限;省略时默认使用 Owner |
1 | Witness 权限;只用于 SR 出块签名,不能授权普通交易 |
2–9 | Active 权限,按账户内 Active 列表顺序从 2 开始分配 |
当 Permission_id 不为 0 时,目标权限必须是 Active 类型,并且当前交易的合约类型必须在该权限的 operations 位图中开放。否则节点会拒绝交易,常见错误包括 Permission type is wrong! 和 Permission denied!。
多签校验的严格性
多签不是“能识别多少签名就算多少权重”的宽松模型。节点校验时会严格检查签名集合:
- 签名数量不能超过目标权限中的密钥数量。
- 每个签名恢复出的地址都必须属于目标权限的
keys列表。 - 未知地址签名不会被当作 0 权重忽略,而是会导致整笔交易失败。
- 同一密钥重复签名也会导致校验失败。
因此,多签收集流程应只让目标权限中的地址签名,并在广播前使用 wallet/getsignweight 检查当前权重。
费用
账户权限和多签交易涉及两类链参数费用。实际集成时应通过 wallet/getchainparameters 查询实时值,不要硬编码。
| 费用 | 链参数 | 主网默认值 | 触发条件 |
|---|---|---|---|
| 更新账户权限费 | #22 getUpdateAccountPermissionFee | 100 TRX | 每笔 AccountPermissionUpdateContract |
| 多签附加费 | #23 getMultiSignFee | 每个额外签名 1 TRX | 交易携带超过 1 个签名时,从第 2 个签名开始逐个计费 |
这些费用叠加在交易本身的带宽或能量成本之上。
示例:配置 2-of-3 多签账户
以下载荷把账户 Owner 权限改为 2-of-3,并创建一个 Active 权限:
{
"owner_address": "TYourAccount...XX",
"owner": {
"type": 0,
"id": 0,
"permission_name": "owner",
"threshold": 2,
"keys": [
{ "address": "TKey1...AA", "weight": 1 },
{ "address": "TKey2...BB", "weight": 1 },
{ "address": "TKey3...CC", "weight": 1 }
]
},
"witness": null,
"actives": [
{
"type": 2,
"id": 2,
"permission_name": "active0",
"threshold": 1,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [
{ "address": "TKey1...AA", "weight": 1 }
]
}
]
}交易确认后,Owner 级操作需要三个密钥中的任意两个共同签名;active0 权限可由 TKey1 单独签名,但只能执行 operations 位图开放的操作。
端到端签名流程参见账户权限管理交易示例。
API
| API | 说明 |
|---|---|
wallet/accountpermissionupdate | 更新账户权限 |
wallet/getsignweight | 查看部分签名交易当前权重 |
wallet/getapprovedlist | 查看已签名地址 |
wallet/broadcasttransaction | 广播完整签名交易 |
相关资源
- 账户权限管理交易示例 — 端到端多签演练
- 签名校验 — 签名恢复与多签聚合规则
- 账户与密钥 — 账户和地址基础
- 系统合约类型详情 — 完整
ContractType参考 - TIP-16 — 账户权限管理规范
Updated 26 days ago