账户权限管理

TRON 账户如何通过权限、权重和签名阈值实现多方共管。

TRON 账户不必只由一个私钥控制。通过账户权限管理(TIP-16),一个账户可以把控制权拆分给多个地址:每个地址配置一个权重,交易只有在有效签名权重之和达到阈值后才会通过校验。

这套机制通常用于金库、多方运营账户、SR 节点运维和企业热/冷密钥分离。Owner 权限负责最高控制权,Active 权限负责日常操作范围,Witness 权限仅服务于 SR 出块签名。

📘

前置阅读

权限类型

每个 TRON 账户都围绕三类权限工作:

权限用途关键约束
Owner账户最高控制权,可执行任意系统合约,也可修改账户权限结构新账户默认只有 Owner 权限
WitnessSR 账户用于区块生产签名必须且只能包含 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

IDContractType功能
0AccountCreateContract创建账户
1TransferContract转账 TRX
2TransferAssetContract转账 TRC-10 Token
4VoteWitnessContract为超级代表候选人投票
5WitnessCreateContract申请成为 SR 候选人
11FreezeBalanceContractStake 1.0 质押 TRX
12UnfreezeBalanceContractStake 1.0 解除质押 TRX
13WithdrawBalanceContract提取投票奖励
16ProposalCreateContract创建治理提案
17ProposalApproveContract批准治理提案
30CreateSmartContract部署智能合约
31TriggerSmartContract调用智能合约
33UpdateSettingContract更新合约调用方资源分摊比例
45UpdateEnergyLimitContract调整合约部署方能量代付上限
46AccountPermissionUpdateContract更新账户权限
48ClearABIContract清除合约 ABI
49UpdateBrokerageContract更新 SR 分成比例(Brokerage)
54FreezeBalanceV2ContractStake 2.0 质押 TRX
55UnfreezeBalanceV2ContractStake 2.0 发起解除质押
56WithdrawExpireUnfreezeContract提取到期的已解除质押 TRX
57DelegateResourceContract代理带宽或能量
58UnDelegateResourceContract撤销资源代理
59CancelAllUnfreezeV2Contract取消所有待处理的解除质押

完整枚举参见系统合约类型详情

位图计算示例

如果一个 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 + VoteWitnessContract120000...设置 ID 1 和 ID 4
TransferContract + UpdateAssetContract028000...设置 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含义
0Owner 权限;省略时默认使用 Owner
1Witness 权限;只用于 SR 出块签名,不能授权普通交易
29Active 权限,按账户内 Active 列表顺序从 2 开始分配

Permission_id 不为 0 时,目标权限必须是 Active 类型,并且当前交易的合约类型必须在该权限的 operations 位图中开放。否则节点会拒绝交易,常见错误包括 Permission type is wrong!Permission denied!

多签校验的严格性

多签不是“能识别多少签名就算多少权重”的宽松模型。节点校验时会严格检查签名集合:

  • 签名数量不能超过目标权限中的密钥数量。
  • 每个签名恢复出的地址都必须属于目标权限的 keys 列表。
  • 未知地址签名不会被当作 0 权重忽略,而是会导致整笔交易失败。
  • 同一密钥重复签名也会导致校验失败。

因此,多签收集流程应只让目标权限中的地址签名,并在广播前使用 wallet/getsignweight 检查当前权重。

费用

账户权限和多签交易涉及两类链参数费用。实际集成时应通过 wallet/getchainparameters 查询实时值,不要硬编码。

费用链参数主网默认值触发条件
更新账户权限费#22 getUpdateAccountPermissionFee100 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广播完整签名交易

相关资源