eosio.system合约分析

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" );

//省略...
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容