多重签名
背景
多重签名功能允许权限分级,每个权限可以对应多个私钥。这使得实现账户的多人联合控制成为可能。本指南引导用户完成TRON的多签名实现和设计。
https://github.com/tronprotocol/TIPs/blob/master/tip-16.md
概念说明
该方案共包含三种权限级别,owner、witness以及active权限,其中owner权限具有执行所有合约的权限,witness权限用于超级代表出块,active是自定义权限(可以组合权限集合),以下将详细说明。
结构说明
1. Account修改
message Account {
...
Permission owner_permission = 31;
Permission witness_permission = 32;
repeated Permission active_permission = 33;
}
在账户结构中新增三个权限属性,分别是 owner_permission、witness_permission 和 active_permission,其中 active_permission 是个列表,可以指定最多8个。
2. ContractType修改
message Transaction {
message Contract {
enum ContractType {
AccountCreateContract = 0;
...
AccountPermissionUpdateContract = 46;
}
}
}
}
新增一种交易类型 AccountPermissionUpdateContract,用于更新账户权限。
3. AccountPermissionUpdateContract
message AccountPermissionUpdateContract {
bytes owner_address = 1;
Permission owner = 2;
Permission witness = 3;
repeated Permission actives = 4;
}
参数 | 描述 |
---|---|
owner_address | 待修改权限的账户的地址 |
owner | 修改后的 owner 权限 |
witness | 修改后的 witness 权限(如果是 witness ) |
actives | 修改后的 actives 权限 |
该接口是覆盖原账户权限,因此,如果只想修改owner权限,witness(如果是witnss账户)及actives的也需要设置。
4. Permission
message Permission {
enum PermissionType {
Owner = 0;
Witness = 1;
Active = 2;
}
PermissionType type = 1;
int32 id = 2;
string permission_name = 3;
int64 threshold = 4;
int32 parent_id = 5;
bytes operations = 6;
repeated Key keys = 7;//
}
参数 | 描述 |
---|---|
PermissionType | 权限类型,目前仅支持三种权限 |
id | 值由系统自动设置,Owner id=0, Witness id=1, Active id 从2开始递增分配。在执行合约时, 通过该id来指定使用哪个权限,如使用owner权限,即将id设置为0。 |
permission_name | 权限名称,由用户设定,长度限制为32字节 |
threshold | 阈值,只有当参与签名的权重之和超过域值才允许做相应的操作。要求小于Long类型的最大值 |
parent_id | 目前只能为0 |
operations | 当前权限可执行的合约类型。共32字节(256位),每位代表一个系统合约类型的权限,为1时表示拥有执行该系统合约的权限。 具体示例参考下文:"active权限中operations编码示例" |
keys | 共同拥有该权限的地址及权重,最多允许5个key。 |
5. Key
message Key {
bytes address = 1;
int64 weight = 2;
}
参数 | 描述 |
---|---|
address | 拥有该权限的地址 |
weight | 该地址对该权限拥有权重 |
6. Transaction修改
message Transaction {
...
int32 Permission_id = 5;
}
在交易中增加 Permission_id字段,与Permission.id相对应,用于指定使用哪个权限。默认为0,即owner权限。 不允许为1,因为witness权限仅用于出块,不用于对交易进行签名。
Owner权限
OwnerPermission是账户的最高权限,用于控制用户的所有权、调整权限结构,Owner权限也可以执行所有合约。
Owner权限具有以下特性:
- 拥有OwnerPermission的地址可以修改OwnerPermission。
- 当OwnerPermission为空时,默认采用该账户的地址具有owner权限。
- 账户新建时,自动将该账户的地址填充到OwnerPermission中,并默认域值为1,keys中仅包含该账户地址且权重为1。
- 当执行合约时未指定permissionId时, 默认采用OwnerPermission。
Witness权限
超级代表可使用该权限,管理出块节点。非witness账户无该权限。
使用场景示例:一个超级代表在云服务器上部署出块程序,为了账户安全,此时可以将出块权限赋予另一个地址。由于该地址仅具有出块权限,无TRX转出权限,即使该服务器上私钥被泄密,也不会出现TRX丢失。
Witness出块节点的配置:
- 未修改witness权限时,无需特殊配置。
- 修改witness权限后的出块节点,需要在重新配置,配置项如下:
#config.conf
// Optional.The default is empty.
// It is used when the witness account has set the witnessPermission.
// When it is not empty, the localWitnessAccountAddress represents the address of the witness account,
// and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account.
// When it is empty,the localwitness is configured with the private key of the witness account.
//可选项,默认为空。
//用于当witness账户设置了witnessPermission。
//当该值不为空时,localWitnessAccountAddress代表witness账户的地址,localwitness是witnessPermission中的地址的私钥。
//当该值为空时,localwitness配置为witness账户的私钥。
//localWitnessAccountAddress =
localwitness = [
f4df789d3210ac881cb900464dd30409453044d2777060a0c391cbdf4c6a4f57
]
Active权限
Active权限,用于提供一个权限的组合,比如提供一个只能执行创建账户、转账功能的权限。
Active权限有以下特性:
- 拥有OwnerPermission的地址可以修改Active权限
- 拥有执行AccountPermissionUpdateContract权限的地址也能够修改Active权限
- 最多支持8个组合。
- permission的id从2开始自动递增。
- 账户新建时,自动创建一个Active权限,并将该账户的地址填充到其中,默认域值为1,keys中仅包含该账户地址且权重为1。
费用
- 使用更新账户权限时,即 AccountPermissionUpdate 合约,收取100TRX。
- 使用多重签名的交易时,即交易中包括两个及两个以上签名的交易,除交易费用外,另收取1TRX。
- 可通过提议,修改以上费用。
API
修改权限
AccountPermissionUpdateContract
,修改权限步骤如下:
- 使用接口
getaccount
查询账户,并获取原权限 - 修改permission
- 创建合约,签名
- 发送交易
http-demo
http://{{host}}:{{port}}/wallet/accountpermissionupdate
{
"owner_address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700",
"owner": {
"type": 0,
"permission_name": "owner",
"threshold": 2,
"keys": [{
"address": "41F08012B4881C320EB40B80F1228731898824E09D",
"weight": 1
},
{
"address": "41DF309FEF25B311E7895562BD9E11AAB2A58816D2",
"weight": 1
},
{
"address": "41BB7322198D273E39B940A5A4C955CB7199A0CDEE",
"weight": 1
}
]
},
"actives": [{
"type": 2,
"permission_name": "active0",
"threshold": 3,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [{
"address": "41F08012B4881C320EB40B80F1228731898824E09D",
"weight": 1
},
{
"address": "41DF309FEF25B311E7895562BD9E11AAB2A58816D2",
"weight": 1
},
{
"address": "41BB7322198D273E39B940A5A4C955CB7199A0CDEE",
"weight": 1
}
]
}]
}
参数字段的定义及限制,请查看"2.1 结构说明"。
active权限中operations编码示例
operations,是以十六进制编码的序列(小端字节序),共32字节(256位),每一位代表一种系统合约的权限(即执行该类型交易的权限),第n位表示ID为n的系统合约类型的权限,值为1表示拥有执行该操作的权限,值为0表示没有该操作的权限。 不同系统合约类型的ID值请参考下表:
系统合约类型 | ID | 描述 |
---|---|---|
AccountCreateContract | 0 | 创建账户 |
TransferContract | 1 | TRX转账 |
TransferAssetContract | 2 | TRC-10代币转账 |
VoteAssetContract | 3 | 未使用 |
VoteWitnessContract | 4 | 为超级代表投票 |
WitnessCreateContract | 5 | 申请成为超级代表候选人 |
AssetIssueContract | 6 | 发布TRC-10代币 |
WitnessUpdateContract | 8 | 更新超级代表候选人的网站URL |
ParticipateAssetIssueContract | 9 | 购买TRC-10代币 |
AccountUpdateContract | 10 | 更新账户名 |
FreezeBalanceContract | 11 | Stake1.0质押 |
UnfreezeBalanceContract | 12 | 解质押Stake1.0阶段质押的资产 |
WithdrawBalanceContract | 13 | 提取奖励 |
UnfreezeAssetContract | 14 | 解锁发布的TRC10代币 |
UpdateAssetContract | 15 | 更新TRC10通证参数 |
ProposalCreateContract | 16 | 创建提议 |
ProposalApproveContract | 17 | 赞成提议 |
ProposalDeleteContract | 18 | 删除提议 |
SetAccountIdContract | 19 | 设置账户ID |
CreateSmartContract | 30 | 创建智能合约 |
TriggerSmartContract | 31 | 触发智能合约 |
UpdateSettingContract | 33 | 更新合约consume_user_resource_percent |
ExchangeCreateContract | 41 | 创建交易所 |
ExchangeInjectContract | 42 | 给交易所注资 |
ExchangeWithdrawContract | 43 | 从交易所撤资 |
ExchangeTransactionContract | 44 | 在交易所交易 |
UpdateEnergyLimitContract | 45 | 调整智能合约部署者提供的能量上限 |
AccountPermissionUpdateContract | 46 | 更新账户权限 |
ClearABIContract | 48 | 清除合约ABI |
UpdateBrokerageContract | 49 | 更新SR分红比例 |
ShieldedTransferContract | 51 | 匿名交易 |
FreezeBalanceV2Contract | 54 | 质押TRX |
UnfreezeBalanceV2Contract | 55 | 解质押 |
WithdrawExpireUnfreezeContract | 56 | 提取已过锁定期的解质押本金 |
DelegateResourceContract | 57 | 资源代理 |
UnDelegateResourceContract | 58 | 取消资源代理 |
为了方便用户阅读,下面以二进制大端字节序为例,说明如何计算operations的值:位数以0开始从左到右对应系统合约类型的ID,将二进制大端字节序列转换成十六进制小端字节序列,即为operations的值,示例如下:
允许的操作权限 | 二进制编码大端序 | 二进制编码小端序 | 十六进制编码小端序 |
---|---|---|---|
TransferContract(1) & VoteWitnessContract(4) | 01001000 00000000 00000000 ... | 00010010 00000000 00000000 ... | 12 00 00 ... |
TransferContract(1) & UpdateAssetContract(15) | 01000000 00000001 00000000 ... | 000000010 10000000 00000000 ... | 02 80 00 ... |
所有系统合约 | 11111110 11111111 11111000 ... | 01111111 11111111 00011111 ... | 7F FF 1F ... |
active权限中operations的计算示例
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bouncycastle.util.encoders.Hex;
enum ContractType {
UndefinedType(-1),
AccountCreateContract(0),
TransferContract(1),
TransferAssetContract(2),
VoteAssetContract(3),
VoteWitnessContract(4),
WitnessCreateContract(5),
AssetIssueContract(6),
WitnessUpdateContract(8),
ParticipateAssetIssueContract(9),
AccountUpdateContract(10),
FreezeBalanceContract(11),
UnfreezeBalanceContract(12),
WithdrawBalanceContract(13),
UnfreezeAssetContract(14),
UpdateAssetContract(15),
ProposalCreateContract(16),
ProposalApproveContract(17),
ProposalDeleteContract(18),
SetAccountIdContract(19),
CustomContract(20),
CreateSmartContract(30),
TriggerSmartContract(31),
GetContract(32),
UpdateSettingContract(33),
ExchangeCreateContract(41),
ExchangeInjectContract(42),
ExchangeWithdrawContract(43),
ExchangeTransactionContract(44),
UpdateEnergyLimitContract(45),
AccountPermissionUpdateContract(46),
ClearABIContract(48),
UpdateBrokerageContract(49),
ShieldedTransferContract(51),
MarketSellAssetContract(52),
MarketCancelOrderContract(53),
FreezeBalanceV2Contract(54),
UnfreezeBalanceV2Contract(55),
WithdrawExpireUnfreezeContract(56),
DelegateResourceContract(57),
UnDelegateResourceContract(58);
private int num;
ContractType(int num) { this.num = num; }
public static ContractType getContractTypeByNum(int num) {
for(ContractType type : ContractType.values()){
if(type.getNum() == num)
return type;
}
return ContractType.UndefinedType;
}
public int getNum() {
return num;
}
}
public class operationsEncoderAndDecoder{
// Description: get operations code according to the input contract types
public static String operationsEncoder(ContractType[] contractId){
List<ContractType> list = new ArrayList<ContractType>(Arrays.asList(contractId));
byte[] operations = new byte[32];
list.forEach(e -> {
int num = e.getNum();
operations[num / 8] |= (1 << num % 8);
});
return Hex.toHexString(operations);
}
// Description: get all allowable contract types according to the operations code
public static List<String> operationsDecoder(String operations){
List<String> contractIDs = new ArrayList<>();
byte[] opArray = Hex.decode(operations);
for(int i=0;i<32;i++) // 32 bytes
{
for(int j=0;j<8;j++)
{
if((opArray[i]>>j & 0x1) ==1) {
contractIDs.add(ContractType.getContractTypeByNum(i*8+j).name());
}
}
}
return contractIDs;
}
public static void main(String[] args) {
ContractType[] contractID = {ContractType.TransferContract, ContractType.VoteWitnessContract, ContractType.FreezeBalanceV2Contract };
String operations = operationsEncoder(contractID);
System.out.println(operations);
// output: 1200000000004000000000000000000000000000000000000000000000000000
List<String> contractIDs = operationsDecoder(operations);
contractIDs.forEach(e ->{
System.out.print(e + " ");
});
// output: TransferContract VoteWitnessContract FreezeBalanceV2Contract
}
}
构建并执行多重签名交易
1、创建交易,与非多重签名交易的构建过程相同
2、指定Permission_id,默认为0,表示owner-permission
3、用户A签名,将签名后交易通过其他方式发送给B。
4、用户B签名,将签名后交易通过其他方式发送给C。
…
n、最后一个完成签名的用户,将交易广播到节点。
n+1、验证多重签名的权重之和大于域值则接受交易,否则拒绝交易
代码示例:
其他多签相关接口
- 查询已签名地址
curl -X POST http://127.0.0.1:8090/wallet/getapprovedlist -d '{"transaction"}'
rpc GetTransactionApprovedList(Transaction) returns (TransactionApprovedList) { }
- 查询交易签名权重
curl -X POST http://127.0.0.1:8090/wallet/getsignweight -d '{"transaction"}'
rpc GetTransactionSignWeight (Transaction) returns (TransactionSignWeight) {}
在创建帐户时会自动生成所有者权限和活动权限。 owner-permission包含一个账户地址,即该账户地址,权限和阈值均设置为1. active-permission包含一个账户地址,即该账户地址,权限和阈值设置为1,操作是“7fff1fc0033efb07000000000000000000000000000000000000000000000000”,这意味着支持除AccountPermissionUpdateContract之外的所有操作。
Updated 21 days ago