美文网首页
eosio.system合约分析

eosio.system合约分析

作者: rectinajh | 来源:发表于2018-05-30 18:26 被阅读1302次

    eos有个核心理念,EOS代币的所有者给予用户按比例的网络带宽、存储空间、运算能力。好处是用户拥有1%的EOS代币,无论网络其余部分的负载如何,他将始终可以访问1%的网络带宽。恶意攻击者只能消耗根据其EOS代币占比拥有的相应比例的网络资源。不会影响整个eos网络。

    本文目的是分析eos这一核心理念是如何实现的?

    根据eos官网找到了代码实现的范围
    https://github.com/EOSIO/eos/tree/master/contracts/eosio.system

    eosio.system是EOS的智能合约,eos三个核心功能:
    1,用户抵押token,可以投票给区块生成者(block producer),就是目前竞争火热的21个超级节点,还有获得社区提案(worker proposal)的权利。
    2,设置代理,把投票权移交给其他用户。
    3,抵押token,获得相应的网络带宽,存储空间,运算能力。

    部署合约:

    首先需要创建个钱包,才可以做其它操作

    创建默认钱包
    ./cleos wallet create
    
    设置基础配置智能合约:eosio.bios
    ./cleos set contract eosio ../../contracts/eosio.bios -p eosio -j
    
    设置系统智能合约:eosio.system 部署了该智能合约
    cleos set contract eosio ../../contracts/eosio.system -p eosio
    

    然后才可以有账户发行EOS token,才可以执行,注册producer,投票者下注,投票等操作。

    创建eos token
    ./cleos push action eosio issue '{"to":"eosio","quantity":"1000000000.0000 EOS"}' --permission eosio@active -j
    
    创建账户 bp.a
    ./cleos create account eosio bp.a EOS8dtXWZQWqSv4mk3WPrpMKGywA5pBY1MWxbpSGSLVvV4k98kvxs EOS7fhfs1j5BBQC9bsM5c8c2WZy6NPG6mbAGMuuYJCnKNHfb3vrND
    
    vo.a 押token
    ./cleos push action eosio delegatebw '{"from":"vo.a","receiver":"vo.a","stake_net":"100.0000 EOS","stake_cpu":"100.0000 EOS","stake_storage":"0.0000 EOS"}' --permission vo.a@active
    
    vo.a给 bp.a 投票
    ./cleos push action eosio voteproducer '{"voter":"vo.a","proxy":"","producers":["bp.a"]}' --permission vo.a@active
    

    eosio.system合约源码

    1,eosio.system合约的主要代码在eosio.system.hpp、eosio.system.cpp两个文件中;
    2,eosio.system合约有很多Action,eosio.system.cpp中的EOSIO_ABI宏定义如下:

    EOSIO_ABI( eosiosystem::system_contract,
     (setram)
     // delegate_bandwith.cpp
     (delegatebw)(undelegatebw)(refund)
     (buyram)(buyrambytes)(sellram)
     // voting.cpp
     // producer_pay.cpp
     (regproxy)(regproducer)(unregprod)(voteproducer)
     (claimrewards)
     // native.hpp
     (onblock)
     (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)
    )
    

    3,可以看到,具体的Action实现代码分散到了delegate_bandwith.cpp、voting.cpp、producer_pay.cpp、native.cpp中,下面会进行分析。

    4、eosio.system.hpp中定义了合约类eosiosystem::system_contract,和一些结构体:

    eosio_global_state(全局状态)
    producer_info(生产者信息)
    voter_info(投票人信息)

    5,system_contract类继承自native.hpp中定义的eosiosystem::native类,native类又继承自eosio::contract基类;

    6,system_contract类中定义了system合约的Action,

    以下Action在producer_pay.cpp中实现:

    计算生产者节点收益的相关代码:
    
    //计算一些遗漏的区块,更新指定生产者的区块信息
    void onblock( uint32_t timestamp_slot, account_name producer );
    
    //(生产者)获取回报
    void claimrewards( const account_name& owner );
    
    
    
    //计算根据生产者生产的区块数量,计算每个块的收益    
    eosio::asset system_contract::payment_per_block( double rate, const eosio::asset& token_supply,  uint32_t num_blocks ) {
    const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount) * double(num_blocks)) / double(blocks_per_year) );
    return eosio::asset( payment, token_supply.symbol );
    }
    
    //计算根据生产者的生产时间,计算每秒收益    
    eosio::asset system_contract::supply_growth( double rate, const eosio::asset& token_supply, time seconds ) {
    const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount) * double(seconds)) / double(seconds_per_year) );
    return eosio::asset( payment, token_supply.symbol );
    }
    
    //计算生产者从每次投票中获得的收益(代码部分省略)
    eosio::asset system_contract::payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& pervote_bucket ) {
    eosio::asset payment(0, S(4,EOS));
    //如果每日收益少于100EOS,则没有收益
    const int64_t min_daily_amount = 100 * 10000;
    if ( pervote_bucket.amount < min_daily_amount ) {
         return payment;
    }
    //省略...
    return payment;
    }
    

    以下Action在delegate_bandwidth.cpp中实现:

      //抵押token,获取网络和CPU资源
      //from是抵押者,receiver是token接收者
      //transfer如果设置为true,接收者可以取消抵押,否则抵押者可以随时取消抵押
        void delegatebw(account_name from, 
                account_name receiver,
                asset stake_net_quantity, 
                asset stake_cpu_quantity, 
                bool transfer);
    
    //取消抵押,释放网络和CPU资源
    //from取消抵押后,会失去投票权
    void undelegatebw(  account_name from, 
                    account_name receiver,
                    asset unstake_net_quantity, 
                    asset unstake_cpu_quantity );
    
    //购买指定价值内存,buyer是购买者,receiver是内存接收者
    void buyram( account_name buyer, account_name receiver, asset tokens );
    
    //购买指定大小的内存,支付的EOS会以当前市场价格计算
    void buyrambytes( account_name buyer, account_name receiver, uint32_t bytes   );
    
    //出售内存
    void sellram( account_name receiver, uint64_t bytes );
    
    //取回token,有3天等待期
    void refund( account_name owner );
    

    实现的主要是和资源分配有关的Action:

    //抵押token,获取网络和CPU资源
    //from是抵押者,receiver是token接收者
    //transfer如果设置为true,接收者可以取消抵押,否则抵押者可以随时取消抵押
    void delegatebw(account_name from, 
                account_name receiver,
                asset stake_net_quantity, 
                asset stake_cpu_quantity, 
                bool transfer);
    
    //取消抵押,释放网络和CPU资源
    //from取消抵押后,会失去投票权
    void undelegatebw(  account_name from, 
                    account_name receiver,
                    asset unstake_net_quantity, 
                    asset unstake_cpu_quantity );
    
    //购买指定价值内存,buyer是购买者,receiver是内存接收者
    void buyram( account_name buyer, account_name receiver, asset tokens );
    
    //购买指定大小的内存,支付的EOS会以当前市场价格计算
    void buyrambytes( account_name buyer, account_name receiver, uint32_t bytes );
    
    //出售内存
    void sellram( account_name receiver, uint64_t bytes );
    
    //取回token,有3天等待期
    void refund( account_name owner );
    

    以下Action在voting.cpp中实现

    //注册生产者,会为生产者创建或更新producer_info对象
      void regproducer( const account_name producer, const public_key& producer_key, const std::string& url );
    
    //取消注册
      void unregprod( const account_name producer );
    
    //投票,可以投给多个生产者
    void voteproducer( const account_name voter, const account_name proxy, const std::vector<account_name>& producers );
    
    //注册成为投票代理
    //已经使用了代理的投票者,不能注册为投票代理
    void regproxy( const account_name proxy, bool isproxy );
    

    voting.cpp中包含了投票相关的Action,比较重要的有:

    //根据投票数由高到低,选出21个区块生产者,并更新数据
    void system_contract::update_elected_producers( block_timestamp block_time ) {
    //...    
    }
    
    //用户投票选出生产者
    //参数voter_name表示投票人,proxy表示该账户的代理人
    //参数producers是一个生产者数组
    void system_contract::voteproducer( const account_name voter_name, const account_name proxy, const std::vector<account_name>& producers ) {
    
    //如果已有代理人,表示该账户已经把投票权委托出去了,就不能再投票
    if ( proxy ) {
        eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" );
        //不能委托给自己
        eosio_assert( voter_name != proxy, "cannot proxy to self" );
        require_recipient( proxy );
    } else {
        //一次不能投超过30个生产者
        eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" );
        //检测账户投的生产者列表中的节点是否是唯一且排好序的
        for( size_t i = 1; i < producers.size(); ++i ) {
            eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" );
        }
    }
    
    auto voter = _voters.find(voter_name);
    //需要抵押token才能投票
    eosio_assert( voter != _voters.end(), "user must stake before they can vote" ); 
    //已注册为代理人的账户,不能再委托别人进行投票
    eosio_assert( !proxy || !voter->is_proxy, "account registered as a proxy is not allowed to use a proxy" );
    
    //省略...
    }
    

    相关文章

      网友评论

          本文标题:eosio.system合约分析

          本文链接:https://www.haomeiwen.com/subject/lwhajftx.html