1 多签名操作的概念
回想一下创建账户的命令:
Usage: cleos create account [OPTIONS] creator name OwnerKey [ActiveKey]
一个账户拥有Owner和Active权限。同时账户也能够自定义新的权限。所谓多签名,就是一个账户可以将它的权限指派给其它多个账户,一个操作只有得到这些授权用户签名而得到执行。多签名是加强账户安全性的一个方法。EOS的多签名是由智能合约eosio.msig来进行支持的。
2 多签名实施
创建3个账户并设置权限
首先创建3个key并导入到钱包:
~/eos$ cleos wallet keys
[
"EOS5goTcdfs9DoaC1cNXSHuWqG6zZNNcnwrMdTqoFB8VuJEhK3yRz",
"EOS5p4xfYuHqcKBypvMYqTyvvCTcv3fxijM7yedFYEWDSPbzVMRvY",
"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
]
然后用这3个key分别创建3个账户jack、alice和bob。
查询jack账户的权限:
~/eos$ cleos get account jack
permissions:
owner 1: 1 EOS5goTcdfs9DoaC1cNXSHuWqG6zZNNcnwrMdTqoFB8VuJEhK3yRz
active 1: 1 EOS5goTcdfs9DoaC1cNXSHuWqG6zZNNcnwrMdTqoFB8VuJEhK3yRz
我们打算将jack的Owner和Active权限按照下表授权给alice和bob:
ps:这里有权重weight和门槛threshold,对于owner权限,alice和bob的weight都是1,而threshold为2,则说明owner权限需要alice和bob一起签名操作才能够执行;对于active权限,alice和bob的weight都是1,而threshold为1,则说明active权限只需要alice或bob任何一个签名操作就能够执行。
我们先设置jack的owner权限:
cleos set account permission jack owner '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"alice","permission":"owner"},"weight":1},{"permission":{"actor":"bob","permission":"owner"},"weight":1}],"waits":[]}' -p jack@owner
executed transaction: b9b14d39de24afc32a854252a4c5bae917d9efc669da3e772dfb1e494f74507c 248 bytes 5091 us
# eosio <= eosio::updateauth {"account":"jack","permission":"owner","parent":"","auth":{"threshold":2,"keys":[],"accounts":[{"per...
warning: transaction executed locally, but may not be confirmed by the network yet ]
然后再设置jack的active权限:
~/eos$ cleos set account permission jack active '{"threshold":1,"keys":[],"accounts":[{"permission":{"actor":"alice","permission":"owner"},"weight":1},{"permission":{"actor":"bob","permission":"owner"},"weight":1}],"waits":[]}' owner -p jack@owner
executed transaction: 6c2ed86f680f11aec98d924a6a944f9d3844c7ef49df9129ca9f2bd195607955 264 bytes 397 us
# eosio <= eosio::updateauth {"account":"jack","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[],"accounts":...
warning: transaction executed locally, but may not be confirmed by the network yet ]
此时再查看jack账户的权限,可以看到和权限表一致:
~/eos$ cleos get account jack
permissions:
owner 2: 1 alice@owner, 1 bob@owner,
active 1: 1 alice@owner, 1 bob@owner,
部署eosio.msig合约
我们先创建名为eosio.msig的账户:
~/eos$ cleos create account eosio eosio.msig EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
然后用该账户来发布eosio.msig合约:
~/eos$ cleos set contract eosio.msig build/contracts/eosio.msig -p eosio.msig
Reading WAST/WASM from build/contracts/eosio.msig/eosio.msig.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 049b8cc33bf6462eaa3a7ddc1d01db549198bd045d10aa32888972ec20c9e929 8952 bytes 1320 us
# eosio <= eosio::setcode {"account":"eosio.msig","vmtype":0,"vmversion":0,"code":"0061736d010000000198011760017f0060047f7e7e7...
# eosio <= eosio::setabi {"account":"eosio.msig","abi":"0e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650...
warning: transaction executed locally, but may not be confirmed by the network yet
然后通过账户acctoken发布eosio.token智能合约,并创建名为EOS的代币。这些都完成以后向jack、alice和bob分别派发100个代币。
~/eos$ cleos push action acctoken issue '["jack","100.0000 EOS","memo"]' -p eosio
~/eos$ cleos push action acctoken issue '["alice","100.0000 EOS","memo"]' -p eosio
~/eos$ cleos push action acctoken issue '["bob","100.0000 EOS","memo"]' -p eosio
查询余额,3个账户余额都是100:
~/eos$ cleos get currency balance acctoken jack EOS
100.0000 EOS
~/eos$ cleos get currency balance acctoken alice EOS
100.0000 EOS
~/eos$ cleos get currency balance acctoken bob EOS
100.0000 EOS
发起多签名操作提案
假如jack不在,要想通过bob和alice两个人来审批本属于jack的操作,这就要比jack本人操作要麻烦一点,需要新建一个提案。这个提案让jack给bob发送25个代币,需要alice和bob一起用owner权限来签名。
~/eos$ cleos multisig propose nojack '[{"actor":"alice","permission":"owner"},{"actor":"bob","permission":"owner"}]' '[{"actor":"jack","permission":"owner"}]' acctoken transfer '{"from":"jack","to":"bob","quantity":"25.0000 EOS","memo":"test multisig"}' -p acctoken
executed transaction: 303275fe76711aebeddf99d8ed01086032c97d4e8f44c3f1c4038a7ec139fa7f 328 bytes 17925 us
# eosio.msig <= eosio.msig::propose {"proposer":"acctoken","proposal_name":"nojack","requested":[{"actor":"alice","permission":"owner"},...
warning: transaction executed locally, but may not be confirmed by the network yet ]
multisig合约定义了两个数据表,其中一个approvals表就是记录了提案的审批状态。
~/eos$ cleos get table eosio.msig eosio.msig approvals
{
"rows": [{
"proposal_name": "nojack",
"requested_approvals": [{
"actor": "alice",
"permission": "owner"
},{
"actor": "bob",
"permission": "owner"
}
],
"provided_approvals": []
}
],
"more": false
}
可以看到现在有2个提案需要审批,放在requested_approvals中。
审批提案
alice审批通过提案:
~/eos$ cleos multisig approve eosio.msig nojack '{"actor":"alice","permission":"owner"}' -p alice@owner
executed transaction: 93a101ef6a131acba69028aa0599f6bcf4c3ab4bd66f5476b0f64bd0ec493737 216 bytes 433 us
# eosio.msig <= eosio.msig::approve {"proposer":"eosio.msig","proposal_name":"nojack","level":{"actor":"alice","permission":"owner"}}
warning: transaction executed locally, but may not be confirmed by the network yet ]
bob审批提案:
~/eos$ cleos multisig approve eosio.msig nojack '{"actor":"bob","permission":"owner"}' -p bob@owner
executed transaction: 512edc5c7b30a7b97a9100a4a4f2fa63d7c741d0730e2134a09afdf195789bb9 216 bytes 372 us
# eosio.msig <= eosio.msig::approve {"proposer":"eosio.msig","proposal_name":"nojack","level":{"actor":"bob","permission":"owner"}}
warning: transaction executed locally, but may not be confirmed by the network yet ]
提案都通过了,可以开始执行了:
~/eos$ cleos get table eosio.msig eosio.msig approvals{
"rows": [{
"proposal_name": "nojack",
"requested_approvals": [],
"provided_approvals": [{
"actor": "alice",
"permission": "owner"
},{
"actor": "bob",
"permission": "owner"
}
]
}
],
"more": false
}
执行提案
执行提案用命令:
~/eos$ cleos multisig exec eosio.msig nojack -p eosio.msig
Error 3090003: Provided keys, permissions, and delays do not satisfy declared authorizations
Ensure that you have the related private keys inside your wallet and your wallet is unlocked.
可是执行出错了,这是什么原因呢?原因就是multisig
没有权限执行jack@owner
许可,这是自然的。如果随便部署一个合约都能执行别的账户的许可,这就是天大的安全问题。所以我们需要给这个multisig
一个系统权限。注意,我们现在用的自测的nodeos节点,部署的时候没有给它系统权限,主网和测试网络上的eosio.multisig
合约都已经拥有了系统权限。
我们执行这样一个命令就好了:
~/eos$ cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio
executed transaction: fb64ed4c3a28eab846c350a83e05ac6ff836cc292ebe70716605246c22965078 192 bytes 39788 us
# eosio <= eosio::setpriv {"account":"eosio.msig","is_priv":1}
warning: transaction executed locally, but may not be confirmed by the network yet ]
再次去执行提案,这次成功了:
~/eos$ cleos multisig exec eosio.msig nojack -p eosio.msig
executed transaction: 0cd43fe1de36ea35114bf1510132a8efc1d7a54809bb10ba60d96d3ec58527a7 336 bytes 526 us
# eosio.msig <= eosio.msig::exec {"proposer":"eosio.msig","proposal_name":"nojack","executer":"eosio.msig"}
warning: transaction executed locally, but may not be confirmed by the network yet ]
查询余额,看到已经转账成功:
~/eos$ cleos get currency balance acctoken jack
75.0000 EOS
~/eos$ cleos get currency balance acctoken bob
125.0000 EOS