原創(chuàng)不易,轉(zhuǎn)載請(qǐng)注明出處https://steemit.com/eos/@camphortree/eos-dpos
eos的出塊流程大致如下:
Plain Text
........
//啟動(dòng)生產(chǎn)插件
producer_plugin::plugin_startup();
........
//出塊循環(huán)
my->schedule_production_loop();
.........
//出塊
auto result = start_block();
..........
//簽名和提交
auto res = self->maybe_produce_block();
..........
此外:
// 下一次塊的時(shí)間
const fc::time_point block_time = calculate_pending_block_time();
//
以上步驟的核心在于:auto result = start_block();
這個(gè)函數(shù)更跟下去會(huì)發(fā)現(xiàn),重點(diǎn)在于:
Plain Text
chain.start_block(block_time, blocks_to_confirm);
這個(gè)函數(shù)才是dops的關(guān)鍵
void start_block( block_timestamp_type when, uint16_t confirm_block_count, controller::block_status s ) {
FC_ASSERT( !pending );
?
FC_ASSERT( db.revision() == head->block_num, "",
("db.revision()", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
?
auto guard_pending = fc::make_scoped_exit([this](){
pending.reset();
});
?
pending = db.start_undo_session(true);
?
pending->_block_status = s;
//由當(dāng)前區(qū)塊頭創(chuàng)建一個(gè)新的block_state ---->>>>> 11111
pending->_pending_block_state = std::make_shared<block_state>( *head, when ); // promotes pending schedule (if any) to active
pending->_pending_block_state->in_current_chain = true;
//確認(rèn)鏈上的區(qū)塊 ----->>>>> 22222
pending->_pending_block_state->set_confirmed(confirm_block_count);
//更新激活的生產(chǎn)者 ----->>>> 33333
auto was_pending_promoted = pending->_pending_block_state->maybe_promote_pending();
const auto& gpo = db.get<global_property_object>();
if( gpo.proposed_schedule_block_num.valid() && // if there is a proposed schedule that was proposed in a block ...
( *gpo.proposed_schedule_block_num <= pending->_pending_block_state->dpos_irreversible_blocknum ) && // ... that has now become irreversible ...
pending->_pending_block_state->pending_schedule.producers.size() == 0 && // ... and there is room for a new pending schedule ...
!was_pending_promoted // ... and not just because it was promoted to active at the start of this block, then:
)
{
// Promote proposed schedule to pending schedule.
if( !replaying ) {
ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
("proposed_num", *gpo.proposed_schedule_block_num)("n", pending->_pending_block_state->block_num)
("lib", pending->_pending_block_state->dpos_irreversible_blocknum)
("schedule", static_cast<producer_schedule_type>(gpo.proposed_schedule) ) );
}
pending->_pending_block_state->set_new_producers( gpo.proposed_schedule );
db.modify( gpo, [&]( auto& gp ) {
gp.proposed_schedule_block_num = optional<block_num_type>();
gp.proposed_schedule.clear();
});
?
std::cout<<"\n========555==========\n";
std::cout<< fc::json::to_string(*pending->_pending_block_state)<<"\n";
std::cout<<"==========555========\n";
}
11111,22222,33333這三步涉及到的數(shù)據(jù)結(jié)構(gòu)是block_state
{
"id": "0000058af1b33d45e4ec927e52b74e8568422f45245dc0399c144bdff6dc16d8",
"block_num": 1418,
"header": {
"timestamp": "2018-08-04T07:31:47.500",
"producer": "accountnum33",
"confirmed": 0,
"previous": "0000058980ac0382075af4216ddbd7be1eae1690a278d7cc04a61570f307b39d",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "eaadc508183ba966551e48dba3a44505a95e6a42d7a53f435db39c3dec3584c9",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_KVyKdpLpEXPQUvRR5jZL4FMYvFDNic6tyvX6icLXFKhoriskCg21esduAceX2cZDv2GwcB12TxdneeKMwfzWB2TckZpZvQ"
},
"dpos_proposed_irreversible_blocknum": 1370,
"dpos_irreversible_blocknum": 1370,
"bft_irreversible_blocknum": 0,
"pending_schedule_lib_num": 1369,
"pending_schedule_hash": "b4ea72a3e20628a54028e681258cd1e6a46b20ae07210836f29087f9f8f37346",
"pending_schedule": {
"version": 1,
"producers": [ ]
},
"active_schedule": {
"version": 1,
"producers": [
{
"producer_name": "accountnum11",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
},
{
"producer_name": "accountnum22",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
},
{
"producer_name": "accountnum33",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
}
]
},
"blockroot_merkle": {
"_active_nodes": [
"0000058980ac0382075af4216ddbd7be1eae1690a278d7cc04a61570f307b39d",
"ab53f4807abffafbcf15fa6edd6ffe72cf73d18689403e389127015b4fd1e544",
"0275481b63dcb217603558835292d4057d39f9a5d41c9d5302230d379a992b18",
"af944001e02b80671b6ea50e5f83969fc2db5e56671ff83700a9018336d0fc58",
"e1ed7b7a82f5507110497fd41f2098a269ffbe8202de0f57393b4aeb27792434",
"5a36ca2325d5f7b2de22b98de7cf70c0a06cf391fc17f1d242b964d16146dee9"
],
"_node_count": 1417
},
"producer_to_last_produced": [
[
"accountnum11",
1394
],
[
"accountnum22",
1406
],
[
"accountnum33",
1418
],
[
"eosio",
1370
]
],
"producer_to_last_implied_irb": [
[
"accountnum11",
1370
],
[
"accountnum22",
1370
],
[
"accountnum33",
1370
]
],
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt",
"confirm_count": [
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
],
"confirmations": [ ],
"block": {
"timestamp": "2018-08-04T07:31:47.500",
"producer": "accountnum33",
"confirmed": 0,
"previous": "0000058980ac0382075af4216ddbd7be1eae1690a278d7cc04a61570f307b39d",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "eaadc508183ba966551e48dba3a44505a95e6a42d7a53f435db39c3dec3584c9",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_KVyKdpLpEXPQUvRR5jZL4FMYvFDNic6tyvX6icLXFKhoriskCg21esduAceX2cZDv2GwcB12TxdneeKMwfzWB2TckZpZvQ",
"transactions": [ ],
"block_extensions": [ ]
},
"validated": true,
"in_current_chain": true
}
第一步:從當(dāng)前塊頭出發(fā),生成一個(gè)新的block_state。
........
result.producer_to_last_implied_irb[prokey.producer_name] = result.dpos_proposed_irreversible_blocknum;
result.dpos_irreversible_blocknum = result.calc_dpos_last_irreversible();
?
/// grow the confirmed count
static_assert(std::numeric_limits<uint8_t>::max() >= (config::max_producers * 2 / 3) + 1, "8bit confirmations may not be able to hold all of the needed confirmations");
?
// This uses the previous block active_schedule because thats the "schedule" that signs and therefore confirms _this_ block
auto num_active_producers = active_schedule.producers.size();
uint32_t required_confs = (uint32_t)(num_active_producers * 2 / 3) + 1;
?
if( confirm_count.size() < config::maximum_tracked_dpos_confirmations ) {
result.confirm_count.reserve( confirm_count.size() + 1 );
result.confirm_count = confirm_count;
result.confirm_count.resize( confirm_count.size() + 1 );
result.confirm_count.back() = (uint8_t)required_confs;
} else {
result.confirm_count.resize( confirm_count.size() );
memcpy( &result.confirm_count[0], &confirm_count[1], confirm_count.size() - 1 );
result.confirm_count.back() = (uint8_t)required_confs;
}
.......
當(dāng)前3個(gè)生產(chǎn)節(jié)點(diǎn),required_confs為3,所以11111結(jié)束后,confirm_count中會(huì)壓入3,即當(dāng)前出產(chǎn)塊所需的確認(rèn)個(gè)數(shù)。
下面直接給出幾個(gè)解釋:
confirm_count:區(qū)塊所需確認(rèn)個(gè)數(shù)表,從當(dāng)前出產(chǎn)塊往前推,最后的元素為當(dāng)前出產(chǎn)塊所需的確認(rèn)個(gè)數(shù)
producer_to_last_implied_irb:由生產(chǎn)者確定的不可逆區(qū)塊候選名單
dpos_irreversible_blocknum:不可逆區(qū)塊
dpos_proposed_irreversible_blocknum:候選不可逆區(qū)塊
active_schedule:已激活的生產(chǎn)者列表
有了對(duì)這幾個(gè)定義的解釋,代碼變得很清晰
//計(jì)算不可逆區(qū)塊,將不可逆區(qū)塊候選名單中從小到大排,選出1/3處的區(qū)塊號(hào)作為不可逆區(qū)塊
uint32_t block_header_state::calc_dpos_last_irreversible()const {
vector<uint32_t> blocknums; blocknums.reserve( producer_to_last_implied_irb.size() );
for( auto& i : producer_to_last_implied_irb ) {
blocknums.push_back(i.second);
}
/// 2/3 must be greater, so if I go 1/3 into the list sorted from low to high, then 2/3 are greater
?
if( blocknums.size() == 0 ) return 0;
/// TODO: update to nth_element
std::sort( blocknums.begin(), blocknums.end() );
return blocknums[ (blocknums.size()-1) / 3 ];
}
上面的程序中出現(xiàn)兩次3分之幾的算法,第一次是required_confs,沒毛病,一個(gè)區(qū)塊要得到2/3個(gè)生產(chǎn)者的確認(rèn)。但是得到2/3的確認(rèn)與不可逆區(qū)塊的聯(lián)系不僅僅是這個(gè),嚴(yán)格來說,不可逆區(qū)塊是從不可逆區(qū)塊候選名單中選擇出來的。
第11111步之后的json
{
"id": "0000000000000000000000000000000000000000000000000000000000000000",
"block_num": 1419,
"header": {
"timestamp": "2018-08-04T07:31:48.000",
"producer": "accountnum11",
"confirmed": 1,
"previous": "0000058af1b33d45e4ec927e52b74e8568422f45245dc0399c144bdff6dc16d8",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne"
},
"dpos_proposed_irreversible_blocknum": 1370,
"dpos_irreversible_blocknum": 1370,
"bft_irreversible_blocknum": 0,
"pending_schedule_lib_num": 1369,
"pending_schedule_hash": "b4ea72a3e20628a54028e681258cd1e6a46b20ae07210836f29087f9f8f37346",
"pending_schedule": {
"version": 1,
"producers": [ ]
},
"active_schedule": {
"version": 1,
"producers": [
{
"producer_name": "accountnum11",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
},
{
"producer_name": "accountnum22",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
},
{
"producer_name": "accountnum33",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
}
]
},
"blockroot_merkle": {
"_active_nodes": [
"f8a83438724a996caaa42231c39b757bec3d1b6fb0bd2c982812eb2f7fadc377",
"ab53f4807abffafbcf15fa6edd6ffe72cf73d18689403e389127015b4fd1e544",
"0275481b63dcb217603558835292d4057d39f9a5d41c9d5302230d379a992b18",
"af944001e02b80671b6ea50e5f83969fc2db5e56671ff83700a9018336d0fc58",
"e1ed7b7a82f5507110497fd41f2098a269ffbe8202de0f57393b4aeb27792434",
"2553b9e4b8225b0f311c2a382fccd027e90f909319616b75933b56f19d20c440"
],
"_node_count": 1418
},
"producer_to_last_produced": [
[
"accountnum11",
1419
],
[
"accountnum22",
1406
],
[
"accountnum33",
1418
],
[
"eosio",
1370
]
],
"producer_to_last_implied_irb": [
[
"accountnum11",
1370
],
[
"accountnum22",
1370
],
[
"accountnum33",
1370
]
],
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt",
"confirm_count": [
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3
],
"confirmations": [ ],
"block": {
"timestamp": "2018-08-04T07:31:48.000",
"producer": "accountnum11",
"confirmed": 1,
"previous": "0000058af1b33d45e4ec927e52b74e8568422f45245dc0399c144bdff6dc16d8",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne",
"transactions": [ ],
"block_extensions": [ ]
},
"validated": false,
"in_current_chain": false
}
到第22222步,這個(gè)函數(shù)確定了候選不可逆區(qū)與確認(rèn)列表的關(guān)系
num_prev_blocks是指當(dāng)前節(jié)點(diǎn)最后一次出塊到現(xiàn)在的間隔,本文使用3個(gè)節(jié)點(diǎn),故間隔為24
比如出塊順序?yàn)閍ccountnum33--》accountnum11--》accountnum22--》accountnum33
accountnum33會(huì)把自己的塊確認(rèn)一次
accountnum11的時(shí)候會(huì)把33出過的塊和自己確認(rèn)一次。。。。
確認(rèn)就是將confirmed數(shù)組的相應(yīng)元素減去1,第一步得到的json中:
"confirm_count":[2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3]
此時(shí)num_prev_blocks = 24
所以以下程序的工作是先將confirm_count元素從尾到頭減去1,最多遍歷num_prev_blocks和confirm_count大小中最小的。
"confirm_count":[2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,2]
由于出現(xiàn)了“0”元素,將0元素的區(qū)塊號(hào)(1406)記錄在dpos_proposed_irreversible_blocknum中,然后在更新數(shù)組,將0之前的元素去掉。
"confirm_count":[1,1,1,1,1,1,1,1,1,1,1,1,2]
所以這樣看來,dpos_proposed_irreversible_blocknum就是本生產(chǎn)節(jié)點(diǎn)在本塊確定的候選不可逆區(qū)塊。而這個(gè)參數(shù)會(huì)在下一次出塊時(shí)打包進(jìn)producer_to_last_implied_irb。
void block_header_state::set_confirmed( uint16_t num_prev_blocks ) {
/*
idump((num_prev_blocks)(confirm_count.size()));
?
for( uint32_t i = 0; i < confirm_count.size(); ++i ) {
std::cerr << "confirm_count["<<i<<"] = " << int(confirm_count[i]) << "\n";
}
*/
header.confirmed = num_prev_blocks;
?
int32_t i = (int32_t)(confirm_count.size() - 1);
uint32_t blocks_to_confirm = num_prev_blocks + 1; /// confirm the head block too
while( i >= 0 && blocks_to_confirm ) {
--confirm_count[i];
//idump((confirm_count[i]));
if( confirm_count[i] == 0 )
{
uint32_t block_num_for_i = block_num - (uint32_t)(confirm_count.size() - 1 - i);
dpos_proposed_irreversible_blocknum = block_num_for_i;
//idump((dpos2_lib)(block_num)(dpos_irreversible_blocknum));
?
if (i == confirm_count.size() - 1) {
confirm_count.resize(0);
} else {
memmove( &confirm_count[0], &confirm_count[i + 1], confirm_count.size() - i - 1);
confirm_count.resize( confirm_count.size() - i - 1 );
}
?
return;
}
--i;
--blocks_to_confirm;
}
}
第22222步之后的輸出json為:
{
"id": "0000000000000000000000000000000000000000000000000000000000000000",
"block_num": 1419,
"header": {
"timestamp": "2018-08-04T07:31:48.000",
"producer": "accountnum11",
"confirmed": 24,
"previous": "0000058af1b33d45e4ec927e52b74e8568422f45245dc0399c144bdff6dc16d8",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne"
},
"dpos_proposed_irreversible_blocknum": 1406,
"dpos_irreversible_blocknum": 1370,
"bft_irreversible_blocknum": 0,
"pending_schedule_lib_num": 1369,
"pending_schedule_hash": "b4ea72a3e20628a54028e681258cd1e6a46b20ae07210836f29087f9f8f37346",
"pending_schedule": {
"version": 1,
"producers": [ ]
},
"active_schedule": {
"version": 1,
"producers": [
{
"producer_name": "accountnum11",
"block_signing_key": "EOS8mUftJXepGzdQ2TaCduNuSPAfXJHf22uex4u41ab1EVv9EAhWt"
},
{
1,
1,
1,
1,
1,
1,
1,
1,
2
],
"confirmations": [ ],
"block": {
"timestamp": "2018-08-04T07:31:48.000",
"producer": "accountnum11",
"confirmed": 1,
"previous": "0000058af1b33d45e4ec927e52b74e8568422f45245dc0399c144bdff6dc16d8",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"schedule_version": 1,
"header_extensions": [ ],
"producer_signature": "SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne",
"transactions": [ ],
"block_extensions": [ ]
},
"validated": false,
"in_current_chain": true
}
綜上,實(shí)際上dpos在代碼里面使用是分作兩步的。
1,2/3共識(shí),符合2/3認(rèn)可的最高區(qū)塊可以進(jìn)入”由生產(chǎn)者確定的不可逆區(qū)塊候選名單”。由于出塊輪轉(zhuǎn),每個(gè)生產(chǎn)者所能見證的高度是不一樣的。
2,1/3共識(shí),從“由生產(chǎn)者確定的不可逆區(qū)塊候選名單”中選擇1/3高度的地方得到不可逆區(qū)塊。
仔細(xì)一想,2還是加強(qiáng)了不可逆區(qū)塊的共識(shí)。