Ultrain的签名和权限管理

多签名体系

多签名是密码学和区块链里经常提及的词汇, 它对于多方签署/同意执行一个操作有着非常重要的意义--避免不怀好意的人单独行动.
在Ultrain的签名体系中, 有几个非常重要的词语: 钱包(wallet), 帐号(account), 公钥(public key), 私钥(private key). 这些元素组成了区块链签名体系.

  • Wallet
    钱包是用来管理帐号私钥的工具, 它使用某个帐号私钥对交易进行签名. 一个钱包可以管理多个帐号的私钥.
  • Account
    帐号由不超过12个字符的可读文字组成, 包括1-5, a-z中的字符. 注册帐号时, 需要关联合法的public key.
  • Public key
    通过非对称加密算法生成的一对公/私钥中的公开部分, 会公布到区块链网络中.
  • Private key
    通过非对称加密算法生成的一对公/私钥中的保密部分, 需要妥善保管, 绝对不可以泄露.

Ultrain中帐号的权限组成

在ultrain的帐号体系中, 一个帐号有两组密钥, 分别称为owneractive, 同时, 每一组密钥同时有阈值(threshold), 权重(weight). 默认情况下, 一个public key的权重为1.

  • owner 一般的作用是管理帐号的其它权限(比如active), 较少使用.
  • active 一般用来签名交易/申请奖励等, 使用用的频率非常高.
  • threshold owner或active权限生效要求的最小值, 默认值为1.
  • weight public key的权重, 默认为1. 在多签名的情况下, 如果多个public key的weight累加起来超过threshold, 那么这个交易就可以执行.

实践

准备工作

我们先准备以下帐号:
test1: 合约部署帐号
jack, rose, tony: 三个测试帐号

1. 设置test1的active权限为多签名

clultrain set account permission test1 active '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"jack","permission":"active"},"weight":1},{"permission":{"actor":"rose","permission":"active"},"weight":1},{"permission":{"actor":"tony","permission":"active"},"weight":1}],"waits":[]}' owner -p [email protected]

以上命令将test1的active权限为多签名, 它的threshold为2, jack, rose, tony三个帐号的weight都是1. 这意味着只要jack, rose, tony中的两个人签名之后, 累加的权重就会超过threshold, 这时也就可以执行test1中的action了.
上述命令行的参数是一个JSON对象, 说明如下(其它参数的意义可以通过命令行的参数说明了解):

{
    "threshold": 2, #设置权限阈值为2
    "keys": [
        {
            "key": "UTRxxxxxxxxxxx", #一个合法的公钥
            "weight": 1  #设置这个公钥的权重为1
        },
        # .....  其它更多的key对象
    ], 
    "accounts": [
        {
            "permission": {
                "actor": "rose",  # 使用rose的active签名
                "permission": "active"
            },
            "weight": 1  # 设置rose的权重为1
        },
        # ...... 其它更多的account对象
    
    ],
    "waits": [
        "wait_sec": 1,
        "weight": 1
    ]
}

在上面的参数说明中可以看到, 通过keys和accounts两个对象都可以设置一个签名的权重, 区别在于: 通过keys设置的权限, 是和public key本身产生了关联, 如果后续更新了某个帐号active的public key, 那么要重新设置一遍本命令中的key; 通过account设置的权限, 后续可以随便更新account的public key, 不再需要重设多签名了.
所以, 上述命令的等价的一个设置参数是:

{
    "threshold": 2,
    "keys": [
        {
            "key": "<PUB_KEY_OF_JACK", 
            "weight": 1
        },
        {
            "key": "<PUB_KEY_OF_ROSE", 
            "weight": 1
        },
        {
            "key": "<PUB_KEY_OF_TONY", 
            "weight": 1
        }
    ], 
    "accounts": [
    ],
    "waits": [
    ]
}

2. 取消/更新多签名设置

要取消/更新多签名设置, 只要重新再设置一遍新的权限就可以了.

3. 执行多签名交易

  1. 提交一个多签名交易
    多签名权限设置好之后, 可以使用utrio.msig合约来执行一个需要多方签名的操作了.
clultrain multisig propose betwin '[{"actor": "jack", "permission": "active"},{"actor": "rose", "permission": "active"}]' '[{"actor": "test1", "permission": "active"}]' utrio.token transfer '{"from":"test1", "to":"tony", "quantity":"25.0000 SYS", "memo":"bet arsenal win."}' -p [email protected]

在上面的参数中,
第一个数组 '[{"actor": "jack", "permission": "active"},{"actor": "rose", "permission": "active"}]' 表示希望得到的签名. 其实tony也在可签名的列表中, 但是这个交易是他发起的, 所以避嫌不用自己的签名;
第二个数组 '[{"actor": "test1", "permission": "active"}]' 表示执行Action时使用的签名, 由于test1已经授权给了jack, rose, tony三人中的两人, 所以如果多签名满足了, 那么使用test1的签名是没有问题的.
其它的参数和普通的交易一致.
2. 各签名方reivew交易
现在jack和rose可以在自己的终端上review交易了.

clultrain multisig review tony betwin
  1. 各签名方approve交易
    jack和rose认为交易没有问题, 所以他们同意了这个交易
clultrain multisig approve tony betwin '{"actor": "jack", "permission": "active"}' -p [email protected]
clultrain multisig approve tony betwin '{"actor": "rose", "permission": "active"}' -p [email protected]

如果很不幸的, 已经签名过的帐号反悔了, 他可以通过unapprove操作, 取消自己的签名:

clultrain multisig unapprove tony betwin '{"actor": "jack", "permission": "active"}' -p [email protected]
  1. 设置签名帐号的delegate权限
    签名帐号需要设置[email protected]权限, 才能正常的执行这个代理操作. 在这个例子中, jakc和rose都需要设置[email protected]代理.
clultrain set account permission jack active '{"threshold": 1,"keys": [{"key":"PUB_KEY_OF_JACK","weight": 1}],"accounts": [{"permission":{"actor":"utrio.msig","permission":"utrio.code"},"weight":1}]}' owner -p jack
clultrain set account permission rose active '{"threshold": 1,"keys": [{"key":"PUB_KEY_OF_ROSE","weight": 1}],"accounts": [{"permission":{"actor":"utrio.msig","permission":"utrio.code"},"weight":1}]}' owner -p rose
  1. 签名数超过threshold, 可以执行交易
clultrain multisig exec tony betwin -p [email protected]
  1. 取消多签名交易
    当propose一个多交易之后, 如果要取消的话, 发起人可以使用以下命令来取消:
clultrain multisig cancel tony betwin -p [email protected]

更新帐号的签名信息

  1. 帐号的active的签名可以使用owner的签名来修改.
clultrain set account permission tony active NEW_ACTIVE_PUBLIC_KEY owner -p [email protected]

通过上述命令, tony的active签名已经更新为新的NEW_ACTIVE_PUBLIC_KEY了.

  1. 设置owner权限为多签名
    一般情况下, owner密钥除了管理权限外, 不会用来做普通交易. 如果有需要的话, owner权限也可以设置为多签名的:
clultrain set account permission test1 owner '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"jack","permission":"owner"},"weight":1},{"permission":{"actor":"rose","permission":"owner"},"weight":1},{"permission":{"actor":"tony","permission":"owner"},"weight":1}],"waits":[]}' -p [email protected]

设置签名代理

如果想将自己的权限授权给某人来代理(一般写成 [email protected] ). 比如将accountA代理给utrio.code, 则可以通过下面的命令来设置:

clultrain set account permission accountA active '{"threshold": 1,"keys": [{"key":"PUB_KEY_OF_ACCOUNT_A","weight": 1}],"accounts": [{"permission":{"actor":"accountA","permission":"utrio.code"},"weight":1}]}' owner -p accountA

取消代理:

clultrain set account permission accountA active '{"threshold": 1,"keys": [{"key":"PUB_KEY_OF_ACCOUNT_A","weight": 1}],"accounts": []}' owner -p accountA

Custome Permission定制权限

1.创建新权限

为了降低自己的帐号密钥被泄漏的风险,可以设置新的权限来避免使用owner,设置命令如下:

clultrain set account permission ACCOUNT NEW_Permission_NAME '{"threshold":1,"keys":[{"key":"YOUR_PUB_KEY","weight":1}]}' "active" -p [email protected] 

假设我们注册了一个帐号jack,现在要给[email protected]创建一个新的权限permjack:

clultrain set account permission jack permjack '{"threshold":1,"keys":[{"key":"UTR7V1873J53cVojG3Ptni7FhUigCx9uzeXxw2QkKXjSE3tZPSwmW","weight":1}]}' "active" -p [email protected]

设置成功之后,使用clultrain get account jack会返回如下值:

......
permissions:
     owner     1:    1 UTR53pD3DqK2DxAMkqWttQYpbyeBVUhKFSGe4f1iwH65QNA23tAh4
        active     1:    1 UTR53pD3DqK2DxAMkqWttQYpbyeBVUhKFSGe4f1iwH65QNA23tAh41 [email protected],
           permjack     1:    1 UTR7My7dMhKooMBMr6FaaXwWQfuvT8XhPeVPVgXH7PBJcB9PU8tSy
......
2. 将新权限授权给一个特定合约的action

要将新权限授权给一个特定合约,需要使用到下面的命令:

clultrain set action permission ACCOUNT CONTRACT CONTRACT_ACTION NEW_PERMISSION -p ACCOUNT

这样,ACCOUNT的NEW_PERMISSION权限就授权给了CONTRACT的CONTRACT_ACTION命令,在CONTRACT_ACTION中可以通过Action.requireAuth2()来检查新权限了。
例如:

clultrain set action permission jack jack check permjack -p jack

jack合约的check方法可以使用permjack权限了。

3. 编写一个合约使用新权限

我们写一个合约,定义check方法,在Action.requireAuth2()方法中检查新的权限。

 @action
    check(): void {
        Action.requireAuth2(this.receiver, NAME("permjack"));
        Log.s("Check permission successed.").flush();
    }
4. 将合约部署到jack帐号
clultrain set contrack jack contract_path -p jack
5. 使用新权限调用check
clultrain push action jack check '[]' -p [email protected]

调用成功,产生如下输出:

[email protected]:/Users/liangqin/Public/ultrain-core/build/programs/clultrain> ./clultrain push action jack check '[]' -p [email protected]                                                                                             18-12-25 16:59
executed transaction: 36510a921e50806ac5b9b1e5834eb4a34681c1dd672287f915ea27bd4f48d0cd  104 bytes  375 us
#          jack <= jack::check                  ""
>> Check permission successed.
6. 删除创建的新权限

删除新建的权限,通过两步操作可以完成:
1. 取消合约的授权

clultrain set action permission jack jack check NULL -p jack

2. 删除权限

clultrain set account permission jack permjack 'null' "active" -p [email protected]