bitshares基本概念详解【见证人】

in #bitshares6 years ago (edited)

见证人是什么?

见证人是为区块链打包生成新的区块的实体。每一个见证人由股东批准,打包经验证的交易,生成并签署区块。每一条进入网络的交易最终将被所有见证人验证。

由谁在什么时间来打包生成区块是由被称为Delegated Proof of Stak (DPOS)的共识算法决定的。算法的本质是 BitShares 的股东(BTS的持有者)能通过投票来决定他们期望的块打包者。由获得最多票数的所谓"见证人"来打包生成区块。

见证人是比特股系统中运行服务器的雇员:打包交易出块、为智能货币输入喂价、提供强劲内存满足 100000+ TPS 的交易撮合服务等。

目前比特股这个 DAC 的理事会投票通过的参数是:见证人可以获得系统储备资金池中提供的 witness_pay_per_block指定的奖励(根据 DAC的发展和运营需要可以修改这个参数,网络收取的用户支付的每笔手续费的 20% 则回流到储备资金池;未来如果系统交易量非常大,见证人则需要运行性能更强大的服务器,到时候可以根据需要取消这个奖励或者减少这个奖励,而把网络收取的 20%

交易手续费全部或部分奖励给见证人,总之这些参数都是可以在不硬分叉的情况下进行修改的)。

get_object 2.0.0可以取到这些参数,如下:

      "network_percent_of_fee": 2000,
      "witness_pay_per_block": 100000,

现在每产生一个块可获得1BTS。(参考bitshares研究系列【喂价和资产抵押率】中的精度说明)


怎么成为见证人?

成为见证人好像需要用cli_wallet,而不能直接网页钱包操作,以下用cli_wallet示例。

建立用户

unlocked >>> suggest_brain_key   
suggest_brain_key
{
  "brain_priv_key": "OVERCUT CLINK BROOCH POWDRY CORNCOB RESTYLE THIRDLY DOSSAL ANTOECI ADJECT AMIL HEALER ATAXIA PETROL AMPALEA INVEIN",
  "wif_priv_key": "5JfXK7Ld4ok4RXBkS52Y3QAwxt6UkjBj6xUL9FNcne1V75VQ9rF",
  "pub_key": "BTS7Arpuipwe4Tik2bQubPjWFgWtqoiVuZkosbgfSosP8Hog6W58n"
}
unlocked >>> create_account_with_brain_key "OVERCUT CLINK BROOCH POWDRY CORNCOB RESTYLE THIRDLY DOSSAL ANTOECI ADJECT AMIL HEALER ATAXIA PETROL AMPALEA INVEIN" barnard007 nathan nathan true
create_account_with_brain_key "OVERCUT CLINK BROOCH POWDRY CORNCOB RESTYLE THIRDLY DOSSAL ANTOECI ADJECT AMIL HEALER ATAXIA PETROL AMPALEA INVEIN" barnard007 nathan nathan true
884616ms th_a       wallet.cpp:779                save_wallet_file     ] saving wallet to file wallet.json

wallet.cpp / account_evaluator.cpp

wallet实际调用函数 create_account_with_private_key,从脑钥生成owner key,再由owner key获得active key和memo key,发送 account_create_operation 到节点。

创建帐号是不会传私钥到节点的,只会把公钥发送给节点,私钥总是在自己的钱包中。

节点主要创建帐号代码如下:

   const auto& new_acnt_object = db().create<account_object>( [&]( account_object& obj ){
         obj.registrar = o.registrar;
         obj.referrer = o.referrer;
         obj.lifetime_referrer = o.referrer(db()).lifetime_referrer;

         auto& params = db().get_global_properties().parameters;
         obj.network_fee_percentage = params.network_percent_of_fee;
         obj.lifetime_referrer_fee_percentage = params.lifetime_referrer_percent_of_fee;
         obj.referrer_rewards_percentage = referrer_percent;

         obj.name             = o.name;
         obj.owner            = o.owner;
         obj.active           = o.active;
         obj.options          = o.options;
         obj.statistics = db().create<account_statistics_object>([&](account_statistics_object& s){s.owner = obj.id;}).id;

         if( o.extensions.value.owner_special_authority.valid() )
            obj.owner_special_authority = *(o.extensions.value.owner_special_authority);
         if( o.extensions.value.active_special_authority.valid() )
            obj.active_special_authority = *(o.extensions.value.active_special_authority);
         if( o.extensions.value.buyback_options.valid() )
         {
            obj.allowed_assets = o.extensions.value.buyback_options->markets;
            obj.allowed_assets->emplace( o.extensions.value.buyback_options->asset_to_buy );
         }
   });

升为终身会员

unlocked >>> transfer nathan barnard007 1000000000 BTS "How are you?" true

unlocked >>> upgrade_account barnard007 true

wallet.cpp / account_evaluator.cpp

发送一个 account_upgrade_operation 到节点,节点更新帐号数据。节点主要代码如下:

void_result account_upgrade_evaluator::do_apply(const account_upgrade_evaluator::operation_type& o)
{ try {
   database& d = db();

   d.modify(*account, [&](account_object& a) {
      if( o.upgrade_to_lifetime_member )
      {
         // Upgrade to lifetime member. I don't care what the account was before.
         a.statistics(d).process_fees(a, d);
         a.membership_expiration_date = time_point_sec::maximum();
         a.referrer = a.registrar = a.lifetime_referrer = a.get_id();
         a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - a.network_fee_percentage;
      }
      ...

创建见证人

先要创建一个可以投票的见证对象

unlocked >>> create_witness barnard007 "url.barnard007" true
create_witness barnard007 "url.barnard007" true
{
  "ref_block_num": 46138,
  "ref_block_prefix": 523909841,
  "expiration": "2018-05-12T10:55:20",
  "operations": [[
      20,{
        "fee": {
          "amount": 500000000,
          "asset_id": "1.3.0"
        },
        "witness_account": "1.2.31",
        "url": "url.barnard007",
        "block_signing_key": "BTS5oS4VKJFEHo5wMXhSd3JuxatNw1Zw6qBaY4qa8ru3ZfPHbdQgZ"
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "2035263900a78b2e1bf58715def3714ce4bbd393ebdf8a9ffb4a9ff5ed1b59239054230fbab38a28e7b7ed5866e9b9fa815e99a5a91102065f4ee21018343d4563"
  ]
}

wallet.cpp

wallet发送 witness_create_operation 到节点,节点只做了是否终身会员的判断,就执行创建工作:

object_id_type witness_create_evaluator::do_apply( const witness_create_operation& op )
{ try {
   vote_id_type vote_id;
   db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) {
      vote_id = get_next_vote_id(p, vote_id_type::witness);
   });

   const auto& new_witness_object = db().create<witness_object>( [&]( witness_object& obj ){
         obj.witness_account  = op.witness_account;
         obj.signing_key      = op.block_signing_key;
         obj.vote_id          = vote_id;
         obj.url              = op.url;
   });
   return new_witness_object.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }

投票只能按维护时间每天记录一次,下一次维护时间可以通过"get_object 2.1.0"或者 get_dynamic_global_properties 获得,把"2.1.0"对象数据列出参考:

get_object 2.1.0
[{
    "id": "2.1.0",
    "head_block_number": 46548,
    "head_block_id": "0000b5d4117b93c582547053c8d5be79f252bc16",
    "time": "2018-05-12T11:29:00",
    "current_witness": "1.6.8",
    "next_maintenance_time": "2018-05-13T00:00:00",
    "last_budget_time": "2018-05-12T00:04:40",
    "witness_budget": 0,
    "accounts_registered_this_interval": 1,
    "recently_missed_count": 655624,
    "current_aslot": 244934,
    "recent_slots_filled": "340282366920938463463374607431768211455",
    "dynamic_flags": 0,
    "last_irreversible_block_num": 46540
  }
]

db_main.cpp

维护函数,内部调用更新活动见证人等

void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props)
{
   ...
   update_top_n_authorities(*this);
   update_active_witnesses();
   update_active_committee_members();
   update_worker_votes();
   ...    
}

db_block.cpp

每次产生块都会进行判断,是否到了维护时间,如果到了执行维护函数

void database::_apply_block( const signed_block& next_block )
{ try {
   ...
   bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp);
   ...
   if( maint_needed )
      perform_chain_maintenance(next_block, global_props);
}

这样见证人注册到系统,但不能打包,还需要有人投票。

unlocked >>> vote_for_witness nathan barnard007 true true

要到下一个维护周期结束,才能用 get_global_properties 或者 "get_object 2.0.0"看到见证人信息。


如何给见证人投票?

bitshares wallet

在右上角菜单的"Voting"项,可以对见证人投票:

cli_wallet

给见证人投票可以cli_wallet执行vote_for_witness,以下为给"fox"(id为1.2.167)投票:

vote_for_witness barnard18 1.2.167 true true
{
  "ref_block_num": 19578,
  "ref_block_prefix": 11051924,
  "expiration": "2018-05-09T09:36:03",
  "operations": [[
      6,{
        "fee": {
          "amount": 815,
          "asset_id": "1.3.0"
        },
        "account": "1.2.861586",
        "new_options": {
          "memo_key": "BTS5snEyiDkP6dReWafV4jqoHZYqcg2D8L4n2yUmBipyysLmZsRna",
          "voting_account": "1.2.5",
          "num_witness": 0,
          "num_committee": 0,
          "votes": [
            "1:26"
          ],
          "extensions": []
        },
        "extensions": {}
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "1f576e66c899c549ff19623047646469c3f9944e2c01f7ab4a5e3fcfcdad7cba1f3a9f0627e9af1c2700e393d6340be786365df5f49bf392f2373f70c514b5e949"
  ]
}

注意参数都是帐户名或者id

投票完成后,可以在自己的信息中看到,如下:

get_account barnard18
{
  "id": "1.2.861586",
  ...
  "options": {
    "memo_key": "BTS5snEyiDkP6dReWafV4jqoHZYqcg2D8L4n2yUmBipyysLmZsRna",
    "voting_account": "1.2.5",
    "num_witness": 0,
    "num_committee": 0,
    "votes": [
      "1:26"
    ],
    "extensions": []
  }
  ...
}

votes字段中指定了见证人对象中的vote_id,格式为:vote_type:instance,代码中定义如下:

// vote.hpp
struct vote_id_type
{
   /// Lower 8 bits are type; upper 24 bits are instance
   uint32_t content;

   friend size_t hash_value( vote_id_type v ) { return std::hash<uint32_t>()(v.content); }
   enum vote_type
   {
      committee,
      witness,
      worker,   
      VOTE_TYPE_COUNT
   };
   ...
}

vote_type是个枚举(从0开始计数,committee=0...),所以"1:26"就表示投了witness(见证人)的票,对应见证人对象的vote_id是1:26。

wallet.cpp / account_evaluator.cpp

wallet发送 account_update_operation 给节点,节点调用 verify_account_votes() 做了比较多判断,如见证人是否存在等。

整个代码判断比较复杂,但此处投票更新操作只有更新options,就一行代码。

void_result account_update_evaluator::do_apply( const account_update_operation& o )
{
     ...
     if( o.new_options ) a.options = *o.new_options;
     ...
}

见证人怎么打包

注册为见证人后,就可以通过 get_witness 取得见证对象数据:

unlocked >>> get_witness barnard007
get_witness barnard007
{
  "id": "1.6.13",
  "witness_account": "1.2.31",
  "last_aslot": 0,
  "signing_key": "BTS5oS4VKJFEHo5wMXhSd3JuxatNw1Zw6qBaY4qa8ru3ZfPHbdQgZ",
  "vote_id": "1:24",
  "total_votes": 0,
  "url": "url.barnard007",
  "total_missed": 0,
  "last_confirmed_block_num": 0
}

取得见证人对象id和signing_key,我们需要得到私钥:

unlocked >>> dump_private_keys      
dump_private_keys
[[
    "BTS5oS4VKJFEHo5wMXhSd3JuxatNw1Zw6qBaY4qa8ru3ZfPHbdQgZ",
    "5KFH7QukTZyrBQg4hAjeYgmLpmKx8sXF2BL2zn6apDzjz2KxzGd"
  ]
  ...
]

重新启动节点,指定见证人信息:

./witness_node --data-dir=witness_node_data_dir --enable-stale-production --seed-nodes "[]" --witness-id '"1.6.13"' --private-key '["BTS5oS4VKJFEHo5wMXhSd3JuxatNw1Zw6qBaY4qa8ru3ZfPHbdQgZ", "5KFH7QukTZyrBQg4hAjeYgmLpmKx8sXF2BL2zn6apDzjz2KxzGd"]'

或者在 witness_node_data_dir 目录下的config.ini中指定见证人信息。

正常情况下见证人就能产生块了,“见证人打包”说起来很复杂,其实也就是运行节点自动做了包的签名而已,并不用手工去做什么太多事情。当然见证人需要有良好的硬件条件保证打包的稳定,否则也会失去见证人打包资格。


见证人有无到底有多大影响?

Bitshares采用DPOS共识机制,不像BTC、ETH的POW机制,见证人节点是非常重要的一环,如果没有见证人整个链就无法正常运行了。

见证人的切换主要在db_witness_schedule.cpp中处理,等有时间再单独分析。


感谢您阅读 @chaimyu 的帖子,期待您能留言交流!

Sort:  

你好cn区点赞机器人 @cnbuddy 很开心你能成为cn区的一员。如果我打扰到你,请回复“取消”。

Congratulations @chaimyu! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of comments received

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.034
BTC 63960.62
ETH 3142.95
USDT 1.00
SBD 3.95