先执行
rm -fr /usr/local/include/eosiolib
清理掉旧lib,再编译
sudo ./build.sh EOS
参考:GitHub
A curated list of EOS Ecosystem by SuperONE.
EOS 资源汇总。提交 PR 参考 contributing,提交 issue 点击 此处。
This list is released into the public domain.
SuperONE, robin
本篇将为大家介绍eosio.msig的源码实现,合约代码库详见:eosio.msig。eosio.msig主要有propose、approve、unapprove、cancel、exec、invalidate这几种方法,下面会详细逐一介绍每种方法的功能和实现细节。
eosio.msig合约,在eosio.msig.hpp头文件中,主要定义了以下六个合约方法:
eosio.msig合约头文件
namespace eosio {
class multisig : public contract {
public:
multisig( account_name self ):contract(self){}
void propose();
void approve( account_name proposer, name proposal_name, permission_level level );
void unapprove( account_name proposer, name proposal_name, permission_level level );
void cancel( account_name proposer, name proposal_name, account_name canceler );
void exec( account_name proposer, name proposal_name, account_name executer );
void invalidate( account_name account );
propose方法主要功能是提出提案,对应上篇提到的 cleos multisig propose
命令,传参如下:
为了节省资源开销,propose方法并不会根据 cleos multisig propose
传入的参数一一做解析,而是直接解析input data
/*
propose function manually parses input data (instead of taking parsed arguments from dispatcher)
because parsing data in the dispatcher uses too much CPU in case if proposed transaction is big
If we use dispatcher the function signature should be:
void multisig::propose( account_name proposer,
name proposal_name,
vector<permission_level> requested,
transaction trx)
*/
void multisig::propose() {
constexpr size_t max_stack_buffer_size = 512;
size_t size = action_data_size();
char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) );
read_action_data( buffer, size );
之后,会做一系列前置检验工作:proposer提案账户授权是否正确、交易是否超时、propose_name是否存在、提案通过所需权限是否正确等
require_auth( proposer );
eosio_assert( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" );
//eosio_assert( trx_header.actions.size() > 0, "transaction must have at least one action" );
proposals proptable( _self, proposer );
eosio_assert( proptable.find( proposal_name ) == proptable.end(), "proposal with the same name exists" );
bytes packed_requested = pack(requested);
auto res = ::check_transaction_authorization( buffer+trx_pos, size-trx_pos,
(const char*)0, 0,
packed_requested.data(), packed_requested.size()
);
eosio_assert( res > 0, "transaction authorization failed" );
之后,将提案和提案合约的内容存表,将提案通过所需的权限存入requested_approvals表中,我们上篇文章所提到 cleos get table eosio.msig <proposer account> approvals
命令查询的就是这张表
proptable.emplace( proposer, [&]( auto& prop ) {
prop.proposal_name = proposal_name;
prop.packed_transaction = bytes( buffer+trx_pos, buffer+size );
});
approvals apptable( _self, proposer );
apptable.emplace( proposer, [&]( auto& a ) {
a.proposal_name = proposal_name;
a.requested_approvals.reserve( requested.size() );
for ( auto& level : requested ) {
a.requested_approvals.push_back( approval{ level, time_point{ microseconds{0} } } );
}
});
approve方法的主要功能是通过提案,对应上篇提到的 cleos multisig approve
命令,传参如下
首先,系统会查找提案合约内容,查找 requested_approvals 表中需要通过的权限中,是否有和传入permission匹配项。若有匹配项,将此权限加入 provided_approvals 表,即表示该权限通过此提案,并从 requested_approvals 表中移除该权限。
void multisig::approve( account_name proposer, name proposal_name, permission_level level ) {
require_auth( level );
approvals apptable( _self, proposer );
auto apps_it = apptable.find( proposal_name );
if ( apps_it != apptable.end() ) {
auto itr = std::find_if( apps_it->requested_approvals.begin(), apps_it->requested_approvals.end(), [&](const approval& a) { return a.level == level; } );
eosio_assert( itr != apps_it->requested_approvals.end(), "approval is not on the list of requested approvals" );
apptable.modify( apps_it, proposer, [&]( auto& a ) {
a.provided_approvals.push_back( approval{ level, current_time_point() } );
a.requested_approvals.erase( itr );
});
} else {
old_approvals old_apptable( _self, proposer );
auto& apps = old_apptable.get( proposal_name, "proposal not found" );
auto itr = std::find( apps.requested_approvals.begin(), apps.requested_approvals.end(), level );
eosio_assert( itr != apps.requested_approvals.end(), "approval is not on the list of requested approvals" );
old_apptable.modify( apps, proposer, [&]( auto& a ) {
a.provided_approvals.push_back( level );
a.requested_approvals.erase( itr );
});
}
}
unapprove方法的主要功能是不通过提案,对应上篇提到的 cleos multisig unapprove
命令,传参如下:
首先,系统会查找提案合约内容,查找 provided_approvals 表中通过的权限中,是否有和传入permission匹配项。若有匹配项,将此权限加入requested_approvals 表,即表示该权限还没通过此提案,并从 provided_approvals 表中移除该权限。
void multisig::unapprove( account_name proposer, name proposal_name, permission_level level ) {
require_auth( level );
approvals apptable( _self, proposer );
auto apps_it = apptable.find( proposal_name );
if ( apps_it != apptable.end() ) {
auto itr = std::find_if( apps_it->provided_approvals.begin(), apps_it->provided_approvals.end(), [&](const approval& a) { return a.level == level; } );
eosio_assert( itr != apps_it->provided_approvals.end(), "no approval previously granted" );
apptable.modify( apps_it, proposer, [&]( auto& a ) {
a.requested_approvals.push_back( approval{ level, current_time_point() } );
a.provided_approvals.erase( itr );
});
} else {
old_approvals old_apptable( _self, proposer );
auto& apps = old_apptable.get( proposal_name, "proposal not found" );
auto itr = std::find( apps.provided_approvals.begin(), apps.provided_approvals.end(), level );
eosio_assert( itr != apps.provided_approvals.end(), "no approval previously granted" );
old_apptable.modify( apps, proposer, [&]( auto& a ) {
a.requested_approvals.push_back( level );
a.provided_approvals.erase( itr );
});
}
}
cancel方法的主要功能是取消提案,对应上篇提到的 cleos multisig cancel
命令,传参如下:
首先,先查找表获取提案内容。如果canceler账户和提案账户不同,则在提案交易过期之前,canceler都不能取消提案。若能取消,将提案从表中移除。
void multisig::cancel( account_name proposer, name proposal_name, account_name canceler ) {
require_auth( canceler );
proposals proptable( _self, proposer );
auto& prop = proptable.get( proposal_name, "proposal not found" );
if( canceler != proposer ) {
eosio_assert( unpack<transaction_header>( prop.packed_transaction ).expiration < eosio::time_point_sec(current_time_point()), "cannot cancel until expiration" );
}
proptable.erase(prop);
//remove from new table
approvals apptable( _self, proposer );
auto apps_it = apptable.find( proposal_name );
if ( apps_it != apptable.end() ) {
apptable.erase(apps_it);
} else {
old_approvals old_apptable( _self, proposer );
auto apps_it = old_apptable.find( proposal_name );
eosio_assert( apps_it != old_apptable.end(), "proposal not found" );
old_apptable.erase(apps_it);
}
}
exec方法的主要功能是执行提案,对应上篇提到的 cleos multisig exec
命令,传参如下:
void multisig::exec( account_name proposer, name proposal_name, account_name executer ) {
require_auth( executer );
proposals proptable( _self, proposer );
auto& prop = proptable.get( proposal_name, "proposal not found" );
transaction_header trx_header;
datastream<const char*> ds( prop.packed_transaction.data(), prop.packed_transaction.size() );
ds >> trx_header;
//首先,需要做前置检查,检查交易是否过期
eosio_assert( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" );
approvals apptable( _self, proposer );
auto apps_it = apptable.find( proposal_name );
vector<permission_level> approvals;
//然后,查 provided_approvals 表获取通过提案交易的权限们,对比 inv_table 表,如果权限不在 inv_table 表中或者 last_invalidation_time
//已经小于当前时间,代表权限有效,放入approvals表中。inv_table 表的用途在下一个invalidate方法中介绍
invalidations inv_table( _self, _self );
if ( apps_it != apptable.end() ) {
approvals.reserve( apps_it->provided_approvals.size() );
for ( auto& p : apps_it->provided_approvals ) {
auto it = inv_table.find( p.level.actor );
if ( it == inv_table.end() || it->last_invalidation_time < p.time ) {
approvals.push_back(p.level);
}
}
apptable.erase(apps_it);
} else {
old_approvals old_apptable( _self, proposer );
auto& apps = old_apptable.get( proposal_name, "proposal not found" );
for ( auto& level : apps.provided_approvals ) {
auto it = inv_table.find( level.actor );
if ( it == inv_table.end() ) {
approvals.push_back( level );
}
}
old_apptable.erase(apps);
}
//最后,执行提案。如果交易执行权限检验无误,会发起一个defer延迟合约,去执行提案交易。如果执行成功,
//`cleos get actions <executer account>` 会产生两条actions,一条是exec的交易,一条是提案执行的交易。
bytes packed_provided_approvals = pack(approvals);
auto res = ::check_transaction_authorization( prop.packed_transaction.data(), prop.packed_transaction.size(),
(const char*)0, 0,
packed_provided_approvals.data(), packed_provided_approvals.size()
);
eosio_assert( res > 0, "transaction authorization failed" );
send_deferred( (uint128_t(proposer) << 64) | proposal_name, executer, prop.packed_transaction.data(), prop.packed_transaction.size() );
proptable.erase(prop);
}
invalidate方法的主要功能是:如果account之前通过的提案还未执行,就可以使用该方法将提案一键设置为无效。这个方法主要是解决:账户权限变更时,之前通过但未执行的提案一旦执行会盗取账户权限的问题,详见issue。该方法传参如下:
该功能的实现非常简单,首先,inv_table 是用来存放权限的,它的两个字段 account 和last_invalidation_time 分别是账户名和账户权限最近失效时间。last_invalidation_time 时间之前,account的提案批准权限都不可用,在该时间之后account的提案批准权限才能生效。
因此,如果想使account之前审批通过的所有提案都失效的话,就将 last_invalidation_time 设置为当前时间即可。exec方法在执行之前会检查 inv_table,则包含在 inv_table 中的account,即便批准了该提案,该批准也会作废
void multisig::invalidate( account_name account ) {
require_auth( account );
invalidations inv_table( _self, _self );
auto it = inv_table.find( account );
if ( it == inv_table.end() ) {
inv_table.emplace( account, [&](auto& i) {
i.account = account;
i.last_invalidation_time = current_time_point();
});
} else {
inv_table.modify( it, account, [&](auto& i) {
i.last_invalidation_time = current_time_point();
});
}
}
转载自简书
本篇将为大家介绍eos另一个系统合约eos.msig的主要功能和源码实现细节。eos.msig是eos的提案合约,同样也是cleos multisig命令调用的系统合约,可用于提案、通过/不通提案、执行多重签名交易等功能。由于涉及内容较多,介绍将分为上下两篇,上篇将围绕eos账户权限、cleos multisig命令的使用这几个方面进行介绍,下篇则会为大家介绍eosio.msig的源码实现
回顾一下之前的文章,一个账户最基本的权限owner和active是由公私钥对控制的,然而,eos丰富的权限控制方式,还允许我们将一个账户的权限,下放给其他的账户。比如下面的经典例子:
账户popo的权限情况
permissio | account | weight | threshold |
---|---|---|---|
owner | 2 | ||
@user1 | 1 | ||
@user2 | 1 | ||
active | 1 | ||
@user1 | 1 | ||
@user2 | 1 |
1.我们分别创建三个账户popo11111111、zoin11111111、zoin22222222,每个账户使用不同的公私钥对。
分别创建6对公私钥,分别用于三个账号的owner和active权限
cleos create key --to-console
| 账号 | 权限|公钥 |私钥 |
| ------------ | ------------ | ------------ |
| popo11111111 | owner | EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB | 5JAxr3bM6DwwtcKJ7aVydpoaSA2oyiZ94PjqTpW6uXDZ41VuK22|
| popo11111111 | active | EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T |5KRCeqsHAx1UNTtz7BH5N4SSMe75XMCj3j93TqQRDrYCwbjccoP |
| zoin11111111 | owner | EOS5N3qMPXjtwZpMyPeiYXSmBQbr7Lt5Ro2W8pLqyAzFYQPknoUvZ |5KWYcdZcJ1E8mWtg1Qoq5s1fYXJxMQkLupozfZEUEiu6vn6QNzx |
| zoin11111111 | active | EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao | 5Jwy6VbCwpkmczjYgMNVtr9Nd77aenZcPE8DtvPwtYqztbgMzu4|
| zoin22222222 | owner | EOS6hBy5yioHpcH4SxSe91aH8vCGAhhEifKtp1jZEy7PS2rhJFSER |5Hz3u44Avpf4NCVDQdwZGSVXpbpEdRFczo2Wm9FC14pqcx8mUwM |
| zoin22222222 | active | EOS5TeY2C9bdewrbS58SZnrp5azF5Cq7AXraNJihxaW4hbGeWSaeE |5JFoGdAc6zPG9KdHCHPHFL5XbpEnFmDq61y53Bw3Hm3VuFy7Stk |
2.下面开始创建三个账号
cleos system newaccount 已有账号 将要创建的账号 ownerkey activekey --stake-net '0.1 EOS' --stake-cpu '0.1 EOS' --buy-ram-kbytes 4000
利用我们上面文章《以传统的WEB开发方式,来举例理解Dapp开发》中已经在麒麟测试网创建的账号cryptokylinq
,并在麒麟测试网来创建其他账号。
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq popo11111111 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T --stake-net '0.1 EOS' --stake-cpu '0.1 EOS' --buy-ram-kbytes 4000
executed transaction: ada14edaa2dc356f02f8f19515f3227669887a5a840601d28f8d59238e1c7890 336 bytes 4284 us
# eosio <= eosio::newaccount {"creator":"cryptokylinq","name":"popo11111111","owner":{"threshold":1,"keys":[{"key":"EOS81WjiHefR6...
# eosio <= eosio::buyrambytes {"payer":"cryptokylinq","receiver":"popo11111111","bytes":4096000}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
# eosio <= eosio::delegatebw {"from":"cryptokylinq","receiver":"popo11111111","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# eosio.stake <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:07:44.999 thread-0 main.cpp:458 print_result warning: transaction executed locally, but may not be confirmed by the network yet
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq zoin11111111 EOS5N3qMPXjtwZpMyPeiYXSmBQbr7Lt5Ro2W8pLqyAzFYQPknoUvZ EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao --stake-net '0.1 EOS' --stake-cpu '0.1 EOS' --buy-ram-kbytes 4000
executed transaction: daf4b102f68d7161022c0ac8635d91137a0d2d24072d49fdad13a608e2e03072 336 bytes 5102 us
# eosio <= eosio::newaccount {"creator":"cryptokylinq","name":"zoin11111111","owner":{"threshold":1,"keys":[{"key":"EOS5N3qMPXjtw...
# eosio <= eosio::buyrambytes {"payer":"cryptokylinq","receiver":"zoin11111111","bytes":4096000}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# eosio <= eosio::delegatebw {"from":"cryptokylinq","receiver":"zoin11111111","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# eosio.stake <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:11:22.091 thread-0 main.cpp:458 print_result warning: transaction executed locally, but may not be confirmed by the network yet
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq zoin22222222 EOS6hBy5yioHpcH4SxSe91aH8vCGAhhEifKtp1jZEy7PS2rhJFSER EOS5TeY2C9bdewrbS58SZnrp5azF5Cq7AXraNJihxaW4hbGeWSaeE --stake-net '0.1 EOS' --stake-cpu '0.1 EOS' --buy-ram-kbytes 4000
executed transaction: 7b184ccebaeb2cd2b6cece49ec46abd86b20a1d20b29722d21029dd1abc958f0 336 bytes 2667 us
# eosio <= eosio::newaccount {"creator":"cryptokylinq","name":"zoin22222222","owner":{"threshold":1,"keys":[{"key":"EOS6hBy5yioHp...
# eosio <= eosio::buyrambytes {"payer":"cryptokylinq","receiver":"zoin22222222","bytes":4096000}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
# eosio <= eosio::delegatebw {"from":"cryptokylinq","receiver":"zoin22222222","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
# eosio.token <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# cryptokylinq <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
# eosio.stake <= eosio.token::transfer {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:13:52.457 thread-0 main.cpp:458 print_result warning: transaction executed locally, but may not be confirmed by the network yet
3.将popo11111111的owner权限交出,由zoin11111111和zoin22222222的owner权限控制。每个权限的权重weight是1,而门槛threshold是2,即使用popo11111111的owner权限发送交易,需要zoin11111111和zoin22222222进行多重签名才行
先将popo11111111的owner私钥导入钱包
suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB
查看下popo11111111信息
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions:
owner 1: 1 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB
active 1: 1 EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T
将popo11111111的owner权限交出
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com set account permission popo11111111 owner '{"threshold":2, "keys":[{"key": "EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB"}], "accounts": [{"permission": {"actor": "zoin11111111", "permission": "owner"}, "weight": 1}, {"permission": {"actor": "zoin22222222", "permission": "owner"}, "weight": 1}]}' -p popo11111111@owner
executed transaction: 38317f76ad1eb90601ad9bd2c6720e322196aebbb8bed5afacfd4f7c5098b111 200 bytes 759 us
# eosio <= eosio::updateauth {"account":"popo11111111","permission":"owner","parent":"","auth":{"threshold":2,"keys":[{"key":"EOS...
再次查看popo11111111账户
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions:
owner 2: 60450 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB1 zoin11111111@owner, 1 zoin22222222@owner,
active 1: 1 EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T
已将权限owner转交给了 zoin11111111@owner, 1 zoin22222222@owner
4.将popo11111111的active权限交出,由zoin11111111和zoin22222222的active权限控制。每个权限的权重weight是1,而门槛threshold是1,即使用popo11111111的active权限发送交易,zoin11111111和zoin22222222任意一个账户签名即可
先将popo11111111的owner私钥导入钱包
suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T
将popo11111111的active权限交出
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com set account permission popo11111111 active '{"threshold":1, "keys":[{"key": "EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws"}], "accounts": [{"permission": {"actor": "zoin11111111", "permission": "active"}, "weight": 1}, {"permission": {"actor": "zoin22222222", "permission": "active"}, "weight": 1}]}' -p popo11111111@active
executed transaction: c51dede340204a6561b9ad511efcf1f194075319a97f54e7fce1dbee8b20eb18 200 bytes 748 us
# eosio <= eosio::updateauth {"account":"popo11111111","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[{"key...
再次查看popo11111111账户
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions:
owner 2: 60450 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB1 zoin11111111@owner, 1 zoin22222222@owner,
active 1: 31778 EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws1 zoin11111111@active, 1 zoin22222222@active,
已经权限active转交给1 zoin11111111@active, 1 zoin22222222@active
EOS账户这一节,我们将popo11111111账户的owner和active权限交给了zoin11111111和zoin22222222账户,则popo11111111账户原来的公私钥对就失效了,交易的发送需要zoin11111111和zoin22222222账户授权。
额外提一句,主网启动后,超级节点们会将eosio账户的权限交给eosio.prods账户,而eosio.prods账户是由21个超级节点的账户联合控制的,需要15个节点联合签名才能使用eosio账户,可以避免拿管理员权限作恶的现象
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account eosio
privileged: true
permissions:
owner 1: 1 eosio.prods@active,
active 1: 1 eosio.prods@active,
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account eosio.prods
permissions:
owner 1:
active 15: 1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active,
prod.major 11: 1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active,
prod.minor 8: 1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active,
下面,我们就要介绍cleos multisig命令如何调用eosio.msig合约进行提案、发送多重签名的交易。
1.zoin11111111发起一个转账提案,提案名是transferpopo,将popo11111111账户中的10EOS转给cryptokylinq账户,这之前需要保证popo11111111账户有币。
先给popo11111111转入点EOS
cleos -u http://kylin.fn.eosbixin.com push action eosio.token transfer '["cryptokylinq", "popo11111111","10.0000 EOS","test"]' -p cryptokylinq
再导入zoin11111111的active的私钥
suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao
发起提案
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig propose transferpopo '[{"actor": "zoin11111111", "permission": "active"}, {"actor": "zoin22222222", "permission": "active"}]' '[{"actor": "popo11111111", "permission":"active"}]' eosio.token transfer '{"from": "popo11111111", "to": "cryptokylinq", "quantity":"10.0000 EOS", "memo": "test multisig"}' -p zoin11111111@active
executed transaction: 83cde06310cd6cd74dfb180aa38fa4f0a5d950b6f39a4f963237a5ea6d2c39aa 240 bytes 810 us
# eosio.msig <= eosio.msig::propose {"proposer":"zoin11111111","proposal_name":"transferpopo","requested":[{"actor":"zoin11111111","perm...
详细分析下cleos multisig propose命令参数
- proposal_name:提案名
2.查看提案交易cleos multisig review <proposer> <proposal_name>
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig review zoin11111111 transferpopo
{
"proposal_name": "transferpopo",
"packed_transaction": "4224ab5b000000000000000000000100a6823403ea3055000000572d3ccdcd011042082184402bad00000000a8ed32322e1042082184402bad60a78b1ed25cfd45a08601000000000004454f53000000000d74657374206d756c746973696700",
"transaction": {
"expiration": "2018-09-26T06:16:34",
"ref_block_num": 0,
"ref_block_prefix": 0,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "popo11111111",
"permission": "active"
}
],
"data": {
"from": "popo11111111",
"to": "cryptokylinq",
"quantity": "10.0000 EOS",
"memo": "test multisig"
},
"hex_data": "1042082184402bad60a78b1ed25cfd45a08601000000000004454f53000000000d74657374206d756c7469736967"
}
],
"transaction_extensions": []
}
}
3.查看提案审批情况,provided_approvals为空表示尚未审批,request_approvals表示需要哪些权限进行审批
cleos get table eosio.msig <proposer> approvals
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
"rows": [{
"proposal_name": "transferpopo",
"requested_approvals": [{
"actor": "zoin11111111",
"permission": "active"
},{
"actor": "zoin22222222",
"permission": "active"
}
],
"provided_approvals": []
}
],
"more": false
}
4.通过提案 cleos multisig approve 提案人 提案 权限
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig approve zoin11111111 transferpopo '{"actor": "zoin11111111", "permission": "active"}' -p zoin11111111@active
executed transaction: bcc0495b88d7b897853af11ace59029a32f16f1727de04e4c1fa7fc85e7df1dc 128 bytes 1091 us
# eosio.msig <= eosio.msig::approve {"proposer":"zoin11111111","proposal_name":"transferpopo","level":{"actor":"zoin11111111","permissio...
查看提案审批情况
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
"rows": [{
"proposal_name": "transferpopo",
"requested_approvals": [{
"actor": "zoin22222222",
"permission": "active"
}
],
"provided_approvals": [{
"actor": "zoin11111111",
"permission": "active"
}
]
}
],
"more": false
}
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig approve zoin11111111 transferpopo '{"actor": "zoin22222222", "permission": "active"}' -p zoin22222222@active
executed transaction: 62ef04a0ee345ac604ca9fe7be034a0cb69524b1ed146e22c44a806a03337919 128 bytes 633 us
# eosio.msig <= eosio.msig::approve {"proposer":"zoin11111111","proposal_name":"transferpopo","level":{"actor":"zoin22222222","permissio...
查看提案审批情况
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
"rows": [{
"proposal_name": "transferpopo",
"requested_approvals": [],
"provided_approvals": [{
"actor": "zoin11111111",
"permission": "active"
},{
"actor": "zoin22222222",
"permission": "active"
}
]
}
],
"more": false
}
5.执行提案cleos multisig exec <proposer> <proposal_name> -p 谁想执行都可以
执行前查看账户
4,148.3135 EOS
10 EOS
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig exec zoin11111111 transferpopo -p zoin11111111
executed transaction: caaa900536463207713f6af031ee315125d993f0af56ea91aafff3dcdf8b1353 160 bytes 1098 us
# eosio.msig <= eosio.msig::exec {"proposer":"zoin11111111","proposal_name":"transferpopo","executer":"zoin11111111"}
执行完成后查看账户
4,158.3135 EOS
0 EOS
且提案将被自动删除
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
"rows": [],
"more": false
}
并注意到,该笔转账没有交易记录actions 额,是不是在某些情况,需要隐藏交易记录时,可以通过此方法。。。
某个账户发起一个提案后,需事先明确指定哪些账户/权限,必须全部通过审核后,合约动作才能被执行。
提案操作很消耗CPU Error 3080004: Transaction exceeded the current CPU usage limit imposed on the transaction
cleos -u http://kylin.fn.eosbixin.com system delegatebw cryptokylinq zoin11111111 "0 EOS" "10 EOS"
执行提案时,可能出现下面未知错误
需要部署eosio.system系统合约,并开启提案合约的功能即可解决(具体原理会在介绍eos.system合约的时候介绍)
cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio
本篇为大家介绍了eos的账户权限,以及eosio.msig提案合约如何通过cleos multisig调用使用,如何发起提案、审批提案等。别走开,下一篇将深入源码,分析eosio.msig提案合约是怎么写的。
参考自简书
创建账号时Error 3050003
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq popo EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T --stake-net '0.1 EOS' --stake-cpu '0.1 EOS' --buy-ram-kbytes 4000
Error 3050003: eosio_assert_message assertion failure
如果nodeos启动时开始错误显示
nodeos --verbose-http-errors
Error 3050003: eosio_assert_message assertion failure
Error Details:
assertion failure with message: no active bid for name
根据Details就能看出,由于创建的账户名不属于常规的账户名“1-5,a-z”12位。是需要事先投标购买成功的。