aelf Tech Talks: Developer’s Take on GetConsensusCommand

aelf Developer
aelf
Published in
9 min readAug 16, 2019

--

Episode 3

As stated in the AElf consensus contract standard article, the GetConsensus Command interface is used to obtain information such as the time of the next production block of a public key.

In the implementation of AEDPoS, the input is only a public key, and the call time of the interface implementation method is another reference (actually an important input). On the AElf block chain, when the system calls read-only transactions, the context of contract execution is constructed by itself. The call time is generated by DataTime.UtcNow with its own function library in C#, and then converted into the timestamp data type Timestamp provided by protobuf, which is then passed to contract execution.

In fact, regardless of whether the transaction to be executed is a read-only transaction or not, the time stamp passed from the current contract execution context can be obtained in the contract code through Context.CurrentBlockTime.

This paper will primarily look at how the AEDPoS consensus achieves GetConsensusCommand. Prior to that, there will be a brief introduction to the AEDPoS process for those unfamiliar with the AElf consensus.

AEDPoS Process

Let’s not dwell on the basic concept of DPoS. Let’s assume that the main chain of AElf now elects 17 nodes by vote. We’ll call it (temporarily) the AElf Core Data Center, or CDC. (Corresponding to the concept of BPs (Block Producers) in eos.)

These CDCs were obtained directly from the top 17 candidates by referendum at a certain block height (or time point). Each time the top 17 candidates are re-counted and the CDC reappointed, it is called a Term.

At each stage, all CDCs are produced in Round blocks. Each round has 17 + 1 time slots, and each CDC randomly occupies one of the first 17 time slots. The last time slot is produced by the producer of the additional blocks in this round. Additional block producers initialize the next round of information based on the random number published by each CDC in this round. After 18 slots, the next round begins, completing a cycle.

A round’s data structure is as follows:

There is a map structure in the AEDPoS contract. The key is a long-type Round Number. From 1 to 18, each value is the above-mentioned Round structure. Each block generated by the CDC will update the current or next round of information, so as to promote consensus and block production, and provide a basis for consensus verification.

If you are interested in the technical details, see Section 4.2.4 of the AElf White Paper. For implementation details, you can see the AEDPoS Consensus Contract project on Github.

ConsensusCommand

The structure of the ConsensusCommand has been mentioned in the AElf Consensus Contract Standard:

For the AEDPoS consensus, Hint points the way for what type of blocks CDC will produce next. We provide Hint with a special data structure, AElfConsensus Hint:

Block types are included in Behaviour as follows:

Explanation:

UpdateValue and UpdateValueWithoutPreviousInValue represent a common block that the CDC is going to produce in a particular round. The consensus information that the CDC focuses on updating includes his previous_in_value, the out_value generated in this round, and the in_value code fragments used in this round to generate out_value. (The CDC will encrypt 16 cipher fragments with in_value and other CDC’s public key. The other CDCs can only decrypt them with their own private keys. When the number of decrypted fragments reaches a certain level, the original in_value will be exposed. This is an application of shamir’s secret sharing.

Note: Details can be found on Google and the AElf main chain is implemented with ECDH, for example, if you have the chance to write an article and discuss it later.

In addition, a timestamp is added to the actual_mining_times to trigger the block production behavior. The difference between UpdateValueWithoutPreviousInValue and UpdateValue is that the last round of in_value (previous_in_value) does not need to be published this time, because the current round is the first round, or has just been replaced (a new CDC has been voted in).

NextRound represents that the CDC is the additional block producer of this round (or the remedy — when the designated additional block producer is absent), and initializes the next round of information. The next round of information includes slot arrangement for each CDC and additional block producers for the next round specified by the rules.

NextTerm is similar to NextRound, except that it recalculates the top 17 electives and initializes the next round of information based on the new CDC list.

Nothing is to discover that the input public key is not a CDC.

TinyBlock represents that the CDC has just updated consensus information, but its time slot has not yet passed, and has time to produce a few extra blocks. At present, each time slot can produce up to eight small pieces. The advantage of this approach is to improve the efficiency of block validation (similar to eos).

There is a time slot problem that requires special attention. Since AEDPoS chooses to generate the first round of consensus information in the Genesis Block (i.e. all the initial CDC time slots, etc.), and the Genesis Block should be completely consistent for each node, the first round of consensus information has to be assigned a unified time (Otherwise, the hash values of the Genesis Block would be different). Now it’s 0:00 in year 0001. This will result in an extremely inaccurate time slot for the first round (all CDCs will miss their time slots by more than 2,000 years), so special processing will be done when acquiring the first round of ConsensusCommand.

GetConsensusBehaviour

In the AEDPoS contract, to get the GetConsensusCommand method back to ConsensusCommand, the AElfConsensusBehaviour is first obtained based on the input public key and the call time. Then the AElfConsensusBehaviour is used to determine the next block time, among other information.

The logic here is relatively clear. Perhaps it can be explained by a graph.

GetConsensusBehaviour

For the complete code, see: aelf’s GitHub home page.

Next, we discuss ConsensusCommand for each Behaviour one by one.

GetConsensusCommand — UpdateValueWithoutPreviousInValue

The main function of AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue is to implement the Commitment Scheme (WiKi entry), which contains only one commit phase, but not the reveal phase. Corresponding to the consensus Mining Process stage, which is the first round of each session (including the first, of course, when the chain just started), the CDC will try to generate the first block of this cycle.

If we are in the first round of the first round, we need to read the order of the CDC providing public keys from the Round.real_time_miners_information information of the AEDPoS consensus in this round. We expect the block time to, after order * mining_interval milliseconds.Mining_interval, default to 4000ms.

Otherwise, expect_mining_time is read directly from the Round information, and consensusCommand is returned accordingly.

GetConsensusCommand — UpdateValue

AElfConsensusBehaviour.UpdateValue contains a reveal phase in the Commitment Scheme and a new commit phase. The phase corresponding to the consensus Mining Process is the second round of each session and thereafter, the CDC attempts to generate the first block of this round.

Read directly, the expected_mining_time field corresponds to the public key of the CDC in the Round information of the current round.

GetConsensusCommand — NextRound

AElfConsensusBehaviour.NextRound will generate the sequence and corresponding time slots of each CDC in the next round according to the information published by each CDC in the current round, and push RoundNumber back by a number.

For the CDC designated as the producer of additional blocks in this round, it is sufficient to read the generating time slot of additional blocks in this round.

In order to prevent the designated extra block producer from dropping off the line or leaving the block on another bifurcation (bifurcation occurs in case of network instability), all other CDCs will also get a different time slot for the production of additional blocks, which will stand after synchronizing to any additional block produced by a CDC. The CDCs will keep resetting their scheduler in order to not worry about conflicts.

For the first round of special treatment with: AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue.

GetConsensusCommand — NextTerm

AElfConsensusBehaviour.NextTerm will re-select 17 CDCs based on the current election results to generate information for the first round of the new session. The first round of the first session is not treated specially with AElfConsensusBehaviour.NextRound.

GetConsensusCommand — TinyBlock

AElfConsensusBehaviour.TinyBlock occurs in two situations:

  1. At present, the current CDC is the additional block producer in the previous round. After producing blocks containing NextRound transactions, it needs to continue producing up to seven blocks in the same time slot.
  2. The current CDC has just produced blocks containing UpdateValue transactions, and needs to continue to produce up to seven blocks in the same time slot.

The basic judgment logic is that if the current CDC is the producer of the last additional block, it will divide a time slot of 4000ms into eight 500 ms time slots and distribute it. Otherwise, for the first situation, it will be directly based on the previous one, allocating a reasonable time slot for the number of blocks that have been produced.

Finally, adjust the block execution time limit again

After calculating the time of the next production block according to Behaviour, it is possible that the next fast time will be negative (that is, the current time has exceeded the theoretical time of the next block). In this situation, the block packing time limit can be set to 0. Finally, in order to reserve a certain time for generating system transactions, network delays and so on, the block execution time limit is multiplied by a coefficient (to be optimized).

The complete code above can be seen on github.

AElfProject/AElf

Possible optimization directions

Based on existing logic optimization conditions, it can be implemented as a function if possible to increase code readability (or worse).

The original intention of this article was to sort out the previous code by myself to see if there is any possibility of optimization.

Feel free to review the code and submit any bugs or suggestions to the development team.

— Join the Community:

· Get on our Telegram Discord Slack and Kakao channel

· Follow us on Twitter Reddit and Facebook

· Read weekly articles on the aelf blog

· Catch up with the develop progress on Github

· Telegram community in 한국 ,日本語 ,русский ,العربية ,Deutsch ,ItalianoandTiếng Việt,

· Instagram: aelfblockchain

· YouTube Channel: aelf

For more information, visit aelf.io

--

--