波场多重签名的实现

加密货币网络上的标准交易可称之为单签名交易,因为交易执行只需要一个数字签名。多重签名机制中的交易需要多个签名,给每个签名分配一个权重,交易的签名总权重必须达到预先确定的权重阈值该交易才可执行。通过多重签名,一个账户可以被多几个私钥管理,这个账户创建的交易需要被几个私钥签名后才可执行。本文档讨论多重签名操作权限的细节,以及如何在多重签名中执行用户自定义的操作权限。

背景介绍

多重签名包括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权限,那么可以通过以下步骤来修改权限:

  1. 调用getaccount 接口来查询原始的permission。
  2. 通过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来使用多重签名

  1. 假设有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"
}

结论

通过多重签名操作权限,我们可以更灵活地加强账户的权限控制,满足账户管理的不同需求。

参考资料

github.com/tronprotocol

github.com/tronprotocol

github.com/tronprotocol

关于我们

我们是波场公链核心开发者团队,致力于依托区块链技术打造下一代分布式计算平台,如果您想持续了解我们并获取技术支持,请关注我们的公众号:波场核心开发团队

关于波场公链

波场公链代码仓库: github.com/tronprotocol

波场开发者电报群: t.me/troncoredevscommun

编辑于 2021-10-13 10:42