波场多重签名的实现
加密货币网络上的标准交易可称之为单签名交易,因为交易执行只需要一个数字签名。多重签名机制中的交易需要多个签名,给每个签名分配一个权重,交易的签名总权重必须达到预先确定的权重阈值该交易才可执行。通过多重签名,一个账户可以被多几个私钥管理,这个账户创建的交易需要被几个私钥签名后才可执行。本文档讨论多重签名操作权限的细节,以及如何在多重签名中执行用户自定义的操作权限。
背景介绍
多重签名包括3种权限:owner-permission、witness-permission和active-permission。owner-permission可以执行所有的交易或合约,witness-permission用于产块,active-permission是定制化的权限,是合约权限集的组合。来看以下几种场景:
Alice 开了一家公司,创建了一个公司资金账户,然后把她自己和账户维护者Bob、首席财务官Carlo添加到该账户的owner-permission中。Bob的签名权重是2,Carlo的签名权重是2,Alice是5,owner-permission签名的权重是3。对于某个交易,由于Alice的签名权重比阈值3要大,所以她的单个签名就可以让交易执行。Bob的签名权重比阈值要小,他需要Carol或者Alice的签名才能实现交易;如果Carol同意,总的签名权重就是2+2>3,交易就可以执行。
Alice有很多TRX资产,她是唯一持有账户私钥的人。某一天,Alice由于交通事故不幸去世了;她的所有资产永远冻结在账户里,任何人都无法得到它。假设现在账户支持多重签名,Alice预先给她的账户创建了active-permission,把她的丈夫、儿子的地址加入到active-permission中,给予active-permission操作账户的权限。就算Alice某一天去世了,她的家人也可以操作她的账户。
Alice 开了一家公司,给自己创建了一个商业账户,然后把她自己和账户维护者Bob、首席财务官Carlo添加到该账户的active-permission中。Alice授权active-permission操作该商业账户。某一天,Bob辞职了。为了维护账户安全,Alice可以把Bob从active-permission中移除,那么Bob再也不能操作她的账户了。
Alice有一个witness账户,如果她想把程序部署到一个node上,但是不知道如何部署,以前她不得不把账户的私钥提供给程序管理员。假设现在账户支持多重签名,她可以witness权限授权给管理员。由于这个管理员只有产块权限,没有TRX转账权限,所以即使该管理员在服务器上的私钥被丢失,账户里的TRX也不会丢失。
多重签名机制可以避免以上的缺陷,目标在于:
- 支持账户访问权限控制
- 一个账户可以被多个私钥控制,即使某个私钥丢失也不会账户资产损失
协议细节
首先看下多重签名的协议设计。protocol中相关的结构体包括:
- Account
- Permission
- Key
- Transaction
Account
message Account {
...
Permission owner_permission = 31;
Permission witness_permission = 32;
repeated Permission active_permission = 33;
}
账户权限包括三种角色:owner、witness和active。Owner permission可以执行所有的合约,witness permission用于超级代表(SR),active permission包含一组选择执行权限的集合。Account中相关的属性字段分别是owner_permission、witness_permission和active_permission。active_permission是一个数组,长度必须小于等于8。
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;
}
成员变量operations
的每个比特,1表示true,0表示false,最多支持256种不同的交易或合约。索引序号对应Transaction.ContractType中的定义(下文稍后提到)。例如,operations=0x0100...00(16进制) or 100...0(二进制),仅首位为1,而AccountCreateContract在Transaction.ContractType中的id为0,意味着这个permisson只有执行AccountCreateContract合约的权限。假如operations=0x7f ff 1f c0 03 3e 03 ...(16进制) or 11111110 11111111 11111000 00000011 11000000 01111100 11000000 ...(二进制),第47个比特是0,意味着这个permission不允许执行AccountPermissionUpdateContract
类型的合约。因为如下文所示,AccountPermissionUpdateContract
的ContractType是46(从0开始计算)。operations
的16进制序列是小端编码的,但是对于每个字节,是二进制比特的大端编码。比如这个例子,首个字节是7f,对应二进制编码的1111,1110;第三个字节是1f,对应二进制编码是1111,1000。
Key
message Key {
bytes address = 1;
int64 weight = 2;
}
- address: 账户地址
- weight: 签名权重
ContractType
message Transaction {
message Contract {
enum ContractType {
AccountCreateContract = 0;
...
AccountPermissionUpdateContract = 46;
...
}
}
ContractType type = 1;
...
int32 Permission_id = 5;
}
Transaction结构体中的Permission_id字段对应Permission结构体中的id字段。
Owner Permission
Owner permission是一个账户的最高级权限,用于控制账户的归属、调整权限结构。Owner permission有权执行所有的合约。Owner permission的特征包括:
- 拥有owner permission的账户可以修改owner permission
- 当owner permission为null时,账户的默认owner拥有owner permission
- 当你创建一个新账户,地址会被自动插入到owner permission中,默认权重是1;字段keys仅包含这个地址,并且字段weight权重的值也是1。
- 当合约被执行时而Permission_id没有指定,默认使用owner permission
Witness Permission
超级代表(SR)利用这个权限来管理产块。当且仅当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.
//localWitnessAccountAddress =
localwitness = [
f4df789d3210ac881cb900464dd30409453044d2777060a0c391cbdf4c6a4f57
]
Active Permission
Active permission 由一系列合约执行权限组成,比如创建账户、转账函数,等等。
Active permission 特征:
- 拥有owner permission的账户可以修改active permission
- 拥有AccountPermissionUpdateContract合约执行权限的账户也可以修改active permission -
- actives最多包含8个active permission
- permission_id自动从2开始递增
- 当一个账户被创建后,一个active permission自动被创建,账户地址被插入进去,默认权重是1;字段keys仅包含这个地址,并且weight是1。
Fee
- AccountPermissionUpdateContract消耗100个TRX。
- 如果一个交易包含2个或以上的签名,那么交易费消耗一个额外的TRX。
- 费用可以通过议案来修改。
修改权限
如果一个账户拥有AccountPermissionUpdateContract
权限,那么可以通过以下步骤来修改权限:
- 调用
getaccount
接口来查询原始的permission。 - 通过
AccountPermissionUpdateContract
交易来修改权限。例如:
http://{host}:{port}/wallet/accountpermissionupdate
{
"owner_address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700",
"owner": {
"type": 0,
"id": 0,
"permission_name": "owner",
"threshold": 2,
"keys": [
{
"address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700",
"weight": 1
},
{
"address": "{account_1}",
"weight": 1
},
{
"address": "{account_2}",
"weight": 1
}
]
},
"witness": {
"type": 1,
"id": 1,
"permission_name": "witness",
"threshold": 1,
"keys": [
{
"address": "41F08012B4881C320EB40B80F1228731898824E09D",
"weight": 1
}
]
},
"actives": [
{
"type": 2,
"id": 2,
"permission_name": "active0",
"threshold": 2,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [
{
"address": "{account_3}",
"weight": 1
},
{
"address": "{account_4}",
"weight": 1
},
{
"address": "{account_5}",
"weight": 1
}
]
},
{
"type": 2,
"id": 3,
"permission_name": "active1",
"threshold": 3,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [
{
"address": "{account_6}",
"weight": 1
},
{
"address": "{account_7}",
"weight": 1
},
{
"address": "{account_8}",
"weight": 1
}
]
}
]
}
账户41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700 把owner权限授予自己和account_1、account_2,使用id=0;
给 41F08012B4881C320EB40B80F1228731898824E09D 授予witness权限,使用id=1;
授予active权限给account_3、account_4、account_5,使用id=2,名字是active0;
授予active权限给account_6、account_7、account_8,使用id=3,名字是active1;
active0权限至少需要来自2个账户的签名使之生效,active1权限至少需要来自3个账户的签名使之生效。
3. 创建此AccountPermissionUpdateContract
交易并签名。
4. 广播此交易。
如何使用API来使用多重签名
- 假设有5个账户owner、active1、active2、active3、receiver。第一个账户owner有5000个trx,给第五个账户receiver发1000个TRX,该交易需要第2、3、4个人中的至少2人签名才能成交。
2. owner创建更新账户权限类型的交易。47.252.84.158:8090是某个测试节点fullnode的ip及http服务端口
# curl -X POST http://47.252.84.158:8090/wallet/accountpermissionupdate
{
"owner_address" : "41AF498B43EE098B26926798CFEAE1AB1154EF4430",
"owner": {
"type": 0,
"id": 0,
"permission_name": "owner",
"threshold": 1,
"keys": [
{
"address": "41AF498B43EE098B26926798CFEAE1AB1154EF4430",
"weight": 1
}
]
},
"actives": [
{
"type": 2,
"id": 2,
"permission_name": "active1",
"threshold": 2,
"operations": "7fff1fc0033e0000000000000000000000000000000000000000000000000000",
"keys": [
{
"address": "41A6D58DCB0E0FC0C3FE23CC405D5BD7979E9016FB",
"weight": 1
},
{
"address": "41F04DC975557388CD5D5FBCAAA706D76AAD415E59",
"weight": 1
},
{
"address": "41CC187927EB7D648D779FE363F7915DDCFBF2212B",
"weight": 1
}
]
}
]
}
得到json类型的response,称之为${result_2}。
3. owner利用自己的私钥对交易签名
# curl -X POST http://47.252.84.158:8090/wallet/gettransactionsign
{
"transaction" :${result_2} ,
"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a00"
}
得到json类型的response,称之为${result_3}。
4. owner广播该交易
# curl -X POST http://47.252.84.158:8090/wallet/broadcasttransaction
${result_3}.
5. 任何人创建从owner到receiver的转账交易,指定Permission_id为2;
# curl -X POST http://47.252.84.158:8090/wallet/createtransaction
{
"owner_address": "41AF498B43EE098B26926798CFEAE1AB1154EF4430",
"to_address": "41CA6E0F4BC55CFEC286B3E2F3CB45CBAC87792B78",
"amount": 1000,
"Permission_id" : 2
}
得到json类型的response,称之为${result_5},
把结果${result_5}作为字符串发送给用户active1;
6. 用户active1用自己的私钥对接收到的交易进行签名;
# curl -X POST http://47.252.84.158:8090/wallet/gettransactionsign
{
"transaction" : ${result_5},
"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a11"
}
得到json类型的response,称之为${result_6},
把结果${result_6}作为字符串发送给用户active2;
7. 用户active2用自己的私钥对接收到的交易签名;
curl -X POST http://47.252.84.158:8090/wallet/gettransactionsign
{
"transaction" : ${result_6},
"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a22"
}
得到json类型的response,称之为${result_7}。
8. 用户active2广播交易
# curl -X POST http://47.252.84.158:8090/wallet/broadcasttransaction
${result_7}.
9. 任何人都可以查询接收者(reveiver)账户的余额,来验证交易是否成功执行:
# curl -X POST http://47.252.84.158:8090/wallet/getaccount
{
"address": "41CA6E0F4BC55CFEC286B3E2F3CB45CBAC87792B78"
}
结论
通过多重签名操作权限,我们可以更灵活地加强账户的权限控制,满足账户管理的不同需求。
参考资料
https://github.com/tronprotocol/tips/issues/105
https://github.com/tronprotocol/tips/blob/master/tip-16.md
https://github.com/tronprotocol/wallet-cli#How-to-use-the-multi-signature-feature-of-wallet-cli
关于我们
我们是波场公链核心开发者团队,致力于依托区块链技术打造下一代分布式计算平台,如果您想持续了解我们并获取技术支持,请关注我们的公众号:波场核心开发团队
关于波场公链
波场公链代码仓库: https://github.com/tronprotocol/java-tron
波场开发者电报群: https://t.me/troncoredevscommunity