Proof Of Ethic Consensus Yellowpaper
Updated
June 19, 2024
Abstract
Proof of Ethic (PoE) is a new decentralized consensus algorithm for blockchains and is based on pseudo-random numbers and a scoring system, allowing users with high priority to generate a new block. PoE allows for very fast transaction processing and overcomes multiple challenges that proof of stake (PoS) and proof of work (PoW) experience. PoE is based on a principle of absolute probabilistic equality: all nodes have an equal opportunity to generate the next block, given that they are behaving in a normal way, and as long as they have met score threshold, and are not blacklisted. Moreover, because of its core design, PoE doesn't require any monetary investment to participate in the network as a generator and earn rewards, compared to PoS (monetary stacking) and PoW (expensive mining hardware). Low computational power that PoE requires to operate a node allows PoE based blockchains to run on low power-devices like smartphones and tablets, also minimizing environmental impact.
1. Definitions and Concepts
This chapter contains all the information needed for a full understanding of this document, as well as a list of used terms and definitions.
1.1 Glossary
- Peterson
- Each block/transaction in the blockchain includes a Peterson. A Peterson is a pseudo-random number that is calculated using a combination of the previous blocks hash and creator's public key. Peterson value will allow us to randomly select potential block generators, partners, and enforcers. Moreover, such a choice is easy to verify. Thus, it will be impossible to fake block or transaction validators while working on the network. Peterson calculation below:
- Score
- Score is a measure of defining if a node is operating according to the rules. The weight of a rule is defined by how much a specific rule will impact the current score of a node. The rules are defined in 1.3. When the score of a node is too low, it is considered blacklisted. A users score will depend on which roles within the network they can hold (see 3). The score of each node is recalculated at the addition of each new block to the blockchain.
- Score Group
- A list of nodes' public keys of size score_group_size defined as a network parameter in the genesis.json file.
- Score Distribution
- As defined earlier, each node in the network has a score. As the network evolves, the score of each node will change. The score distribution is the array of all Score Groups.
- Generator
- Simply a block creator. For more details see 3.1.
- Enforcer
- Enforcer is a block validator that is picked randomly based on generator's Peterson value. The result of this work is Enforcement. For more details see 3.2.
- Enforcement
- Object which is generated by an Enforcer during block creation.
- Mempool diff
- Difference between Enforcer's transaction poll and block's transactions. This is needed to minimize the probability of a malicious transaction skipping during block generation. Also a part of Enforcement.
- Partner
- Partner is a transaction validator which is picked randomly based on transaction creator's Peterson value. The result of its work is Partner. For more details see 3.3.
- Signed Peterson
- Object which is generated by Partner during transaction creation.
- Node mode
- There are two types of nodes: full or light. A full node stores all blockchain data while a light node only stores block headers.
- Roles
- All network members have certain roles depending on their scores. Each role performs a specific act. For more details see section 3.
- Oracles
- There are special nodes in the network which can create new accounts, change network parameters, etc. There two main Oracles in the network called Pythia and Thesis. For more details see 3.4.
- Artificial nodes
- PoE consensus requires active users to create blocks and transactions (see 2.1) in the blockchain. The network will consist of several artificial nodes at launch, in order to improve speed and security. They work in exactly the same way as nodes run by <alive> accounts, except that if they participate in the consensus, their rewards will be assigned randomly between <alive> accounts that previously participated in the creation of blocks or transactions. Artificial node can be started by passing a command line argument —artificial. As the network reaches critical mass with live nodes, the artificial nodes will be eliminated.
- Regular nodes
- Nodes ran by <live> accounts.
1.2 Network Parameters
All network parameters are set in genesis.json file in the protocol_config section. They may be changed with a specific Config Poll (see 4.18.5)
| Parameter | Description |
|---|---|
| initial_score | Initial account score upon creation |
| oracle_sign_ratio | Minimal percentage of Oracles COSI signers |
| partner_score | Minimal score value to be a partner (see 3.3) |
| generator_score | Minimal score value to be a generator (see 3.1) |
| enforcer_score | Minimal score value to be an enforcer (see 3.2) |
| speedster_score | Minimal score value to be a speedster (see 3.5) |
| blacklisted_score | Scores below this value will be blacklisted |
| enforcers_amount | Number of enforcers to make a block |
| score_group_size | Group size for PoE (see 2.1) |
| block_size_min | Minimum transactions' peterson sum in a block |
| block_size_gate | Gate for transactions' peterson sum in a block |
| tf_min_contribution | Minimum trust fund contribution (see 4.19) |
| poll_creation_fee | Base creation fee for polls (see 4.18) |
| max_transactions_per_user | Maximum user's transactions per block_tx_frequency |
| block_size_limit | Maximum block size in bytes |
| block_tx_frequency | Frequency for maximum user's transactions |
| auto_poll_duration | Duration for system poll (see 3.5 and 3.6) |
| speedster_threshold | Minimum votes for speedster polls (see 3.5) |
| same_enforcers_in_last_blocks_threshold | Need for score_table statistics (see 2.2.1) |
| same_generator_in_last_blocks_threshold | Need for score_table statistics (see 2.2.1) |
| min_average_score_in_block | Need for score_table statistics (see 2.2.1) |
| peterson_frequency_in_block | Need for score_table statistics (see 2.2.1) |
| block_since_existence | Need for score_table statistics (see 2.2.1) |
| generator_score_block_height_threshold | Need for score_table statistics (see 2.2.1) |
| fullnode_threshold | Minimum votes for storer polls (see 3.6) |
| forks_keep_level | The height of forks resolution. Also we accept blocks which height is < than head's but ≥ (head_height−forks_keep_level) |
| score_price | See Table 1. |
1.3 Score Table Values
All score weights are set in genesis.json file and could be changed by Pythia (see 4.18.5). For more details see 2.2.1.
| Notation | Name |
|---|---|
| Rule#1 | creator_has_different_peterson |
| Rule#2 | block_since_existence |
| Rule#3 | empty_block_penalty |
| Rule#4 | generating |
| Rule#5 | enforcement |
| Rule#6 | partner_has_different_peterson |
| Rule#7 | creator_has_same_peterson |
| Rule#8 | partner_has_same_peterson |
| Rule#9 | dbs_penalty |
| Rule#10 | peterson_is_frequent_in_block_transactions |
| Rule#11 | similar_creators_in_block |
| Rule#12 | not_enough_average_score_in_block |
| Rule#13 | generator_has_its_own_transactions |
| Rule#14 | same_enforcers_in_last_blocks |
| Rule#15 | same_generator_in_last_blocks |
2. Proof of Ethic
Proof of Ethic(PoE) enables network to achieve consensus through randomly choosing the validators (enforcers and partners) who will participate in new block creation. A unique and dynamic scoring system controls permissions of users and also encourages user participation to help achieve consensus. Each component is crucial and helps to ensure correct operation of the network.
2.1 Consensus Specification
2.1.1 Transaction Creation
All transaction creations follow these steps:
- Creation transaction object
When all necessary fields are filled, the transaction is prepared for partner approvement. - Partnership
Choose a pseudo random network participant (partner) using the generated Peterson value and Score Distribution. Partner generates its Signed Peterson and adds it to a partner approvement. Approvement also contains information about transactions for avoiding malicious behavior. If partner node is in full mode, it should generate fullnode proof (see 2.2.2). - Signing
Add a single (or collective for Oracles) signature to a transaction. - Spreading
Broadcast transaction to the network. - Validation
Each node should validate correctness of transaction and partner approvement. If all checks pass, then add it to the transaction pool.
2.1.2 Block Creation
After adding transactions to the pool, each network participant may be a new block generator. Creating a new block is an equal opportunity between all network participants who's score fall within acceptable range.
There are two types of blocks: regular and empty_push.
The algorithm for choosing potential generators for current regular block is as follows:
- Choose Score Group using your generated Peterson value.
- Check if your public key is in Score Group. If not- stop generating.
- Find all direct P2P connections in this Score Group and make a descending list of each nodes Peterson value. We can calculate the Peterson of each member of the group in advance, because it consists of the hash of the previous block and the public key of a particular account.
- The node with the biggest Peterson value amongst the group will be the generator.
- If not- check for a certain period of time. If the block did not come from the network, we check if our node has the next largest Peterson in the group.
- Repeat step 5 until the next block is genererated or it's time for your Peterson value.
Each block and generator creation process contains the following steps:
- Creation of Block object
Create block of regular type, fill its header, Peterson value, and other prepared fields, and add list of transactions. If generating node is a full node, it should generate fullnode proof (see 2.2.2). - Enforcement
Choose pseudo random network participant(enforcer) using your generated Peterson value and Score Distribution.- Enforcer generates special Enforcement, which validates incoming block and chooses next enforcer using its own Peterson value and Score Distribution.
- Enforcer finds the missed transactions in the block according to its own transaction pool. This mempool_diff is added to the Enforcement.
- If generating node is a full node, it should generate fullnode proof (see 2.2.2).
- This step is repetitive for each enforcer in the enforcements chain. When the number of enforcers is equal to network parameter enforcer_amount, then the last enforcer closes the chain and sets the next enforcer to the block generator.
- Signing
Add single signature to block. - Spreading
Broadcast transaction to the network - Validation
Each node should validate correctness of block. - Applying
Block adds to blockchain. All transactions are added in parallel with validation.
In case of all potential generators are inactive or can't generate block every Pythia node may use a <Red Button> and create an empty block of empty_push type to <push> Peterson generating process try to choose other potential generators.
The algorithm for choosing potential generators for current empty_push block is as follows:
- Creation of Block object
Create block of regular type, fill its header and other prepare fields, add EMPTY list of transactions. - Signing
Add COSI signature to block. - Spreading
Broadcast transaction to the network. - Validation
Each node should validate correctness of block. - Applying
Block adds to blockchain.
2.1.3 Transaction Validation
Each transaction gets validated before being added to the pool. The main objective of this is to avoid malicious transactions and perform validation that the transaction was created in the right manner (see 2.1.1). Validation process also validates that each transaction state is valid and the transaction can be applied without issues.
Each validation process contains the following steps:
- Chain id correctness
Check that transaction's chain id is from actual hard fork. - Transaction type disabled
Check that transaction's type is enable. - Nonce correctness
Check that transaction's nonce is correct to prevent Replay Attack. - Not approved
Check that transaction contains valid Signed Peterson approvement:- Correct partner's Peterson value.
- Partner has been selected from the correct Score Group.
- Check partners signature correctness with its public key.
- Creator score
Check that transactions creator is not blacklisted. - Wrong transaction validation
Check that transaction can be applied to the current temporary state. - Wrong signature
Check transaction signature correctness with creator public key.
If any steps fail, the pool will reject the incoming transaction.
2.1.4 Block Validation
Each block validated before applying and entering the blockchain. The main goal is to avoid malicious blocks and validate that the transaction was created in the correct manner (see 2.1.2).
Each validation process contains the following steps:
- Hash correctness
Calculate block digest and compare it with it's hash. - Previous block correctness
Compare previous block hash and head hash. If they are not equal-forks may happens (see 2.3). - Timestamp correctness
Check block for large time variance. - Incorrect Peterson value
Check that generator Peterson value was created correctly. - Incorrect Generator score
Check that generator has score not less than generator_score.
If the block has regular type, then the following steps occur:
- Incorrect potential generators group
Check that generator was in correct Score Group. - Wrong enforcements chain
Check that enforcements chain was created correctly:- Correct first enforcer's Peterson value.
- Enforcer has been selected from the correct Score Group.
- Check enforcer's signature correctness with its public key.
- Check next enforcer selection correctness. Overall enforcers size must equal enforcer_amount.
- These steps are repetitive for each enforcer in enforcements chain.
- Wrong transaction validation
Simultaneously apply and validate transacions' logic on current state. - Wrong signature
Check block signature correctness with generator public key. - Fullnode proof
Also we can check generator's, enforcers' and partners' fullnode proof (3.6).
If block has empty_push type than we have following steps:
- Transaction emptiness
Check that block has no transactions. - Check Oracle generator
Check that generator is Pythia Oracle. - Wrong signature
Check block COSI signature correctness.
If any steps fail, the block will be rejected. After validation the new block will be applied to the blockchain, including the contained transactions.
2.2 Reward and Punishment Mechanism
When a new block passes validation and is applied to the network, each node updates the block participants following states:
- Scores - Node rating, which indicates how node behaved during consensus. Controls user permissions and punishes/rewards users for their network activities.
- Rewards - Amount of tokens earned for generators and validators depending on block content.
2.2.1 Scores
During validation, each node checks partner, enforcer, and generator scores. Each protocol participant should have scores in accordance to their role score range.
Scores are recalculated based on special score tables rules and generator/validator behaviour. All values in Table 2.1 are network parameters described in 1.3.
| Notation | Definition | Sign |
|---|---|---|
| Rule#1 | Generate a different Peterson than the node's partner (as the requester) | + |
| Rule#2 | Having spent a determined time in a blockchain since existence thereof(as the generator) | + |
| Rule#3 | Punish empty push block (as the Pythia generator) | - |
| Rule#4 | Generating a block (as the generator) | + |
| Rule#5 | Acting as an enforcer (as the enforcer) | + |
| Rule#6 | Generate a different Peterson than the node's requester (as the partner) | + |
| Rule#7 | Generate the same Peterson as the node's partner (as the requester) | - |
| Rule#8 | Generate the same Peterson as the node's requester (as the partner) | - |
| Rule#9 | Block size out of gate (as the generator) | - |
| Rule#10 | The provided Peterson is frequent in the generated block transactions (as the generator) | - |
| Rule#11 | Similar transaction creators in a block (as the generator) | - |
| Rule#12 | Average node score in block is under N (as the generator) | - |
| Rule#13 | Generator puts it's own transactions in the block (as the generator) | - |
| Rule#14 | Same enforcers in last N blocks (as the generator) | - |
| Rule#15 | Same block generator in last N blocks (as the generator) | - |
2.2.2 Rewards
There are two base tokens in HELO blockchain: HELO and PENIA - the native reward token. Each token object has it's own set of rules describing how to split rewards between roles (see 3) and specific wallets (see _percentage fields in Table 4.16).
If there is no transaction involving a specific role, its percentage is redistributed between other roles according to the following rules:
Lets say $A_1...A_N$ are percentages of roles involved in block transactions and $B$ - not. Then we calculate <active> sum:
$S = \sum_{i=1} A_i$
And the weight of each active participant in this sum:
$W_i = A_i / S$
After that we can find out how to redistributed $B$ percentage among each <active> role:
$R_i = W_i * B$
There are two main parts in the reward system:
- Fee distribution
Fee of specific token from send transactions (see 4.1) distributed between appropriate partner, generator and enforcers. - Hybrid Block Reward
Mint tokens involving in block's transactions. Then split them in accordance with percentages.
Generator/validators gain rewards once per token in block. This means that the number of send transactions (see 4.1) is not taken into account when distributing rewards, rewards will gain only once.
So, the rewards system works as follows, and will be based on example:
There are 5 transactions in a block.
If the block is filled with:
- 1 HELO Transactions
- 2 SomeCoin Transactions
- 2 SomeCoin2 Transactions
Then the next token rewards will be split: 10 HELO, 10 SomeCoin, 10 SomeCoin2, and 10 PENIA
Moreover, if the block is filled with:
- 4 HELO Transactions
- 1 SomeCoin2 Transaction
Then the next token rewards will be split: 10 HELO, 10 SomeCoin2 and 10 PENIA
Moreover, if the block is filled with:
- 4 HELO Transactions
- 1 PENIA Transaction
Then the next token rewards will be split: 10 HELO and 10 PENIA
Moreover, if the block is filled with:
- 5 HELO Transactions
Then the split will be: 10 HELO, 10 PENIA
Full node proof
In order to motivate users to work as a full node, they are awarded 100 percent of the reward, while light only nodes receive 80 percent. When an account changes from light node to full node (or the reverse), the node automatically sends a change mode transaction (see 4.6) to the network to announce the change. When participating in the consensus, the node must prove that it is still a full node and can receive 100 percent of the reward. This is done by generating what's called fullnode proof. The main difference between a full node and a light node is that a full node saves all block history. So, the proof is to give a random hash of a block from genesis to lib height based on current Peterson value. But light node also can store hashes along with headers without having all blocks info! Therefore, the full node does not just provide the hash of the block, but recalculates its hash by adding the current peterson value and lib height to it, so that it is not possible to store hashes in advance. Thus, we achieve the uniqueness of the proof and unambiguous reproducibility, since other Storers (see 3.6) checking the block can generate the same peterson and get a random corresponding block from the database.
Artificial nodes
You can see more information about <what an artificial node is> in 1.1. As you can see rewards from artificial nodes randomly go to regular nodes. There is a regular tracker that saves the last 100 regular accounts that participated in the consensus. If the reward mechanism sees that the potentially rewarded account is artificial, it randomly chooses the previously acting account from regular tracker and rewards this account. If regular tracker is empty, the rewards go to the appropriate token bank.
Artifical Nodes are intended to be used short-term during the launch of the network to provide stability in case of unexpected circumstances.
2.3 Forks Mechanism
Fork is a situation when more than one valid block comes at the same height. In this case we need to decide which block is more important and, accordingly, such a block will get into the main branch. When a new block is submitted for validation, a check takes place to determine if the block should continue the main branch or if a fork is required (see details about forks_keep_level in 1.2 and LIB in 1.1).
Let's denote:
$block\_height$ − new block's height
$head\_height$ − chain's current head height
$block\_prev\_hash$ − new block's previous block hash
$head\_hash$ − chain's current head hash
Then:
if ($head\_height - forks\_keep\_level$) ≤ $block\_height$ ≤ $head\_height$
and
$block\_prev\_hash \neq head\_hash$
then
fork is happening!
Before incoming block validating and applying, fork module change state to previous block. This process is called branch switching. It's necessary for correct block validation.
If the new block has the same height as chain's head it's not necessary that the new block becomes head of blockchain. Two possible candidates for being a new blockchain head are current head and freshly applied block. To solve who is the new blockchain head, we will use a special challenge (rules written and processed in priority order):
- The biggest Peterson value among candidates generators.
- Block with higher amount of transactions.
- Block with older generator.
If previous head is the challenge winner, then branch switching is performed. If not - we have new fork head! Also forks module clears <dead> branches - the branch, which height less than head on forks_keep_level and block on height $head\_height - forks\_keep\_level - 1$ becomes new LIB.
Branch switching
A few words about the branch switching process and how it works. We keep the old state of only changed objects at height of LIB and call it snapshot which is a list of <old> objects and reference counter - how many times <future> blocks changes a particular object. Also forks module keeps tracking state diffs of individual block which is list of <new> objects and reference counter - how many times current block changes a particular object. So, during branch switching on certain block, we apply snapshot and then apply all necessary state diffs from LIB to the block we need.
When LIB changes, snapshot is updated by reducing reference counter of each changed object according to the deleted state diffs.If counter equals 0 an object is removed from new snapshot version.
It's also worth saying that transaction losses are possible due to branch changes caused by nonce validation to protect chain from replay attack.
2.4 Hard Fork Mechanism
Aim is to prevent not updated nodes from taking part in the updated chain when a hard fork happens in the network.
Chain has it's initial chain_id set in the genesis.json. All hard forks identifiers (height and unique chain id of a fork) are stored as objects in the state. There is a hardcoded HARD_FORK_CHAIN_ID value in the node's code. If a node is up to date HARD_FORK_CHAIN_ID equals the current chain id of a chain. New node that is going to switch to new hard fork rules must have a HARD_FORK_CHAIN_ID value more than the actual chain id by one.
Workflow
If HELO is ready to make a hard fork they make an announcement to the community: <We are ready to make a new Hard Fork. Please, update your nodes>. Everyone needs to update their nodes. These nodes would have new logic + updated hardcoded HARD_FORK_CHAIN_ID value (bigger than current one by one, it's very important).
After some time, Pythia makes a hard_fork transaction (see 4.10). This transaction will create a new hard fork object with updated chain id (now it equal to HARD_FORK_CHAIN_ID). Then updated nodes will switch to the new rules. Nodes that are not up to date will have an error if they receive a block with a new hard_fork transaction.
All magic happens when a transaction is going to be applied and it compares the new chain id with the HARD_FORK_CHAIN_ID value. If node was updated (it has a new hardcoded HARD_FORK_CHAIN_ID) - success. Otherwise, the node receives an error.
2.5 Synchronization Mechanism
If all nodes are working at the same time, their state will be always actual and no synchronization needed. But when node leaves for some period of time, it will skip some transactions/blocks and the current state might not be valid. So, after restart node needs synchronization with other nodes in the network.
In addition, some messages can not reach their receivers, and in that case desynchronization will occures. Thereforte, we have to synchronuization mode: start synchronization and operational synchronization.
Start synchronization
When starts, node broadcast message to require other nodes height in the network. It collects heights and decides which network height is actual now. To prevent from malicious height, median filter is used. Then, node requires blocks on the every height, a node for query is selected with random sample. If during timeout data for some height is not received, the information is queried from other random node. When all blocks for all heights are received, the synchronization completes, and the node is ready to operate.
Operational synchronization
If during work the node receives a block with the height exceeding the actial node height more then 1, it waits some short period of time. If during that period underlying blocks are not received, the node requires those blocks from other nodes in the network. Quering node is selected with random sample. If during timeout data for some height is not received, the information is queried from other random node. When all blocks for all heights are received, the synchronization completes, and the node is ready to operate.
3. Roles
Nodes can be different roles in accordance with their score (see appropriate scores in Table 1.1). These roles give an opportunity to perform different actions in chain. If the node behaves in accordance with the role, then it's rewarded, otherwise - penalized.
3.1 Generator
A block creator according to the PoE consensus described in Section 2.1.2.
3.2 Enforcer
A block validator according to the PoE consensus described in Section 2.1.2.
3.3 Partner
A transaction validator according to the PoE consensus described in Section 2.1.1.
3.4 Oracles
There are two Oracle roles in the HELO blockchain - Pythia and Thesis. They have control over account creation, networking config changes, etc. Each of the Oracles can be predefined in the genesis.json file.
3.4.1 Pythia
Pythia node is responsible for creation/modification of new entities (accounts, tokens, kyc approvals etc.) in the HELO blockchain. Each transaction should be signed by active Pythia Nodes with CoSi (collective signature).
Functionality:
- Create new account. See 4.3
- Block created account. See 4.4
- Unblock previously blocked account. See 4.5
- Give account a badge. See 4.7
- Revoke account's badge. See 4.8
- Make account an Oracle. See 4.3
- Revoke account an Oracle. See 4.12
- Approve for using specific token. See 4.2
- Create new token object in a blockchain. See 4.13
- Update token's properties. See 4.14 and 4.18.6
- Create custom transaction type. See 4.18.3
- Initiate HardFork. See 4.10
- Disable transaction type. See 4.16
- Enable transaction type. See 4.16
3.4.2 Thesis
Thesis node is an Oracle that is responsible for token injection (send tokens directly from the bank without fee). Each transaction should be signed by active Thesis Nodes with CoSi (collective signature).
Functionality:
- Inject token amount for a specific account. See 4.15
3.5 Speedster
Speedster is adapating the blocksize to match network demand.
PoE has fixed block size in bytes, but also has another block size estimation parameter (block_size_min and block_size_gate in 1.2) - the sum of transactions Peterson values in the block.
This mechanism is called DBS - dynamic block size.
These parameters could be changed by the Speedster role. Appropriate nodes check transactions flow in the chain and may create a specific poll 4.18.1. Other Speedster nodes vote for the DBS change, if their transactions flow statistics yield similar results in the poll.
3.6 Storer
Storer role should keep all records of the entire blockchain. So, only a full node can be a storer. This role is responsible for checking fullnode proof correctness and creating a specific poll (see 4.18.2) to punish an account that tries to get full node rewards while acting as a light node.
4. Transactions
To make state changes in the blockchain users need to perform some actions using transactions. All transaction objects contain common fields:
4.0 Common Fields
| Common Fields | Description |
|---|---|
| type | Unique transaction type. Just number value |
| block_height | The height of the block on which the transaction is made |
| creator | Transaction creators id |
| nonce | Transaction nonce for replay attack protection |
| value | Transaction creator's Peterson value |
| chain_id | Chain ID to cut off transactions from other hard fork (see 4.10) |
| partner_value | Partner's Signed Peterson value |
| signature | Ed25519 or Collective Edwards-Curve Digital signature. It depends on if it is Oracle tranasaction or not |
4.1 Send
| Unique Fields | Description |
|---|---|
| to | Token recipient |
| token_id | Unique token object id user wants to send |
| quantity | Number of tokens user wants to send |
Expected behavior: Send tokens. Recipient's account is created if it does not exist.
Signature: Ed25519.
4.2 Approve token
An account object must receive a specific token approval before being able to make a transfer with it.
| Unique Fields | Description |
|---|---|
| account | The one who gets the approval |
| token | Token to be approved |
| expiration | Height limiation of specific token. Zero value considers as <unlimited> |
Expected behavior: An account is given permission to use the token.
Signature: Pythia Ed25519 collective signature.
4.3 Account Create
| Unique Fields | Description |
|---|---|
| nickname | Unique nickname of created account |
| badge | Optional string. Not necessarily unique. Just some badge for account |
| pubkey | Unique public key of created account |
| approves | Permission to use specific tokens |
Expected behavior: Recipient's account is created if it does not exist. Unique nickname must be given to prove account creation via KYC service.
Signature: Pythia Ed25519 collective signature.
4.4 Account Block
| Unique Fields | Description |
|---|---|
| pubkey | Public key of account Pythia wants to block |
Expected behavior: Block existed account (set blacklisted score).
Signature: Pythia Ed25519 collective signature.
4.5 Account Unblock
| Unique Fields | Description |
|---|---|
| pubkey | Public key of account Pythia wants to unblock |
Expected behavior: Unblock blacklisted account.
Signature: Pythia Ed25519 collective signature.
4.6 Change Account's Mode
Default mode on each new account after creation in a state of the blockchain is set as light. To get full rewards (see 2.2.2), user needs to change the mode to full using the appropriate transaction. This transaction is sent automatically when the node switches modes.
It's enough just to launch the node so that it starts in full mode and automatically sends change mode transaction as needed. To start node in a light mode user need to provide command line argument —light.
| Unique Fields | Description |
|---|---|
| mode | Mode (light or full) user wants to set in chain's state |
Expected behavior: An account's mode is changed in blockchain's state.
Signature: Ed25519.
4.7 Create Account's Badge
Some group of accounts could have same badge belonging to a group of people. This account field is more important in polls (see 4.18). The creator of the poll can allow only accounts with a certain badge to participate. So, specific badge may be assigned to specific accounts to be able to take part in voting in specific polls.
| Unique Fields | Description |
|---|---|
| account | The one who gets new badge |
| badge | Badge that the account will receive. Shouldn't be unique |
Expected behavior: Account gets new badge.
Signature: Pythia Ed25519 collective signature.
4.8 Revoke Account's Badge
| Unique Fields | Description |
|---|---|
| account | The one whose badge will be revoked |
Expected behavior: Account's badge is revoked.
Signature: Pythia Ed25519 collective signature.
4.9 Custom Transaction
Make custom transaction (see 4.18.3).
| Unique Fields | Description |
|---|---|
| type | Custom transaction's type |
| fields | List of transaction's fields values |
Expected behavior: Custom transaction will appear in chain.
Signature: Ed25519.
4.10 Hard Fork
For more details see 2.4.
| Unique Fields | Description |
|---|---|
| chain_id | New blockchain's hardfork chain id |
Expected behavior: New hard fork is activated.
Signature: Pythia Ed25519 collective signature.
4.11 Oracle Add
This transaction is needed to add new Oracles to the blockchain.
| Unique Fields | Description |
|---|---|
| oracle | Pythia or Thesis type |
| pubkey | Public key of account that Pythia wants to make Oracle |
| revoke_height | Height limiation of being an Oracle. Zero value considers as <unlimited> |
Expected behavior: New Oracle will be created.
Signature: Pythia Ed25519 collective signature.
4.12 Oracle Revoke
This transaction is needed to revoke Oracles.
| Unique Fields | Description |
|---|---|
| oracle | Pythia or Thesis type |
| account | The one who gets revoked |
Expected behavior: Existed Oracle will be revoked.
Signature: Pythia Ed25519 collective signature.
4.13 Token Create
New token objects can be created in chain using this transaction type. It consists of token_info fields:
| Immutable Fields | Description |
|---|---|
| name | Token's unique name |
| bank_acc | Token's bank account |
| creator_acc | Token's creator account |
| Basic Fields | Description |
|---|---|
| max_supply | Maximum token amount in chain |
| wallet_fee | Payment that is charged when the token is used for the first time |
| tx_fee | Basic fee for send transaction |
| min_transfer | Minimum transafer amount (to prevent spam with send transactions) |
| has_themis_trust_funds | Whether token users can create trust funds with this token |
| Reward Fields | Description |
|---|---|
| max_reward_supply | Token's amount for rewards |
| storers_percentage | Reward percentage for storer actor |
| enforcers_percentage | Reward percentage for block enforcers |
| generators_percentage | Reward percentage for block generator |
| speedsters_percentage | Reward percentage for speedster actor |
| partner_percentage | Reward percentage for transactions' partners |
| foundation_percentage | Reward percentage for foundation trust fund |
| bank_percentage | Reward percentage for token bank account |
| trust_staking_percentage | Reward percentage for custom trust funds staking |
| block_reward | Reward for a block that uses this token |
| slash_type | How to slash block_reward field (by percentage or amount) |
| slashing | Percentage or amount to slash the reward by |
| slash_time | How often slash block_reward field |
| has_reward_slashing | If true, the reward will be slashed every couple of blocks |
| has_use_block_reward | Whether token users should be rewarded |
Expected behavior: New token object is created.
Signature: Pythia Ed25519 collective signature.
4.14 Token Update
Token's Basic fields could be updated using this transaction. Reward fields must be update vid specific poll 4.18.6.
| Unique Fields | Description |
|---|---|
| token_id | Token to update |
| update_fields | Base token fields to update (see Table 4.15) |
Expected behavior: Token's basic fields are created.
Signature: Pythia Ed25519 collective signature.
4.15 Token Inject
Inject new tokens from the bank account to a specific wallet. Similar to send, but overwrite the transaction fees always 0.
| Unique Fields | Description |
|---|---|
| to | Token recipient |
| token_id | Unique token object id Thesis wants to inject |
| quantity | Number of tokens Thesis wants to inject |
Expected behavior: Token amount is transfered to specific account.
Signature: Thesis Ed25519 collective signature.
4.16 Transaction Type Disable
Some transactions could be disabled.
| Unique Fields | Description |
|---|---|
| type | Transaction's type to be disabled (except disable and enable transactions) |
Expected behavior: Transaction disabled.
Signature: Pythia Ed25519 collective signature.
4.17 Transaction Type Enable
Disabled transactions could be enabled.
| Unique Fields | Description |
|---|---|
| type | Transaction's type to be enabled |
Expected behavior: Transaction enabled.
Signature: Pythia Ed25519 collective signature.
4.18 Polls Transactions
HELO blockchain gives an opportunity to create Polls. There are certain types of polls that can be used if users have specific roles. Any user can create custom poll. Regular poll_info may contain basic fiels:
| Common Fields | Description |
|---|---|
| expiration | Poll expiration Unix timestamp |
| candidates | List of json objects candidates |
| badge | Optional string. Indicates the involvement of voting in accounts with a certain badge |
| creation_fee | How much does it cost to create a poll |
| min_votes_count | Minimum votes to consider a poll as successfully completed |
4.18.1 DBS (dynamic block size)
This poll can only be created by Speedster role (see 3.5).
| Unique Fields | Description |
|---|---|
| info | See Table 4.21 |
| is_artificial | Does poll created via artificial node or via regular node |
Expected behavior: DBS poll will be created.
Signature: Ed25519.
4.18.2 Incorrect Fullnode Proof
This poll can only be created by Storer role (see 3.6). This logic is one of the most important parts of the fullnode proof reward mechanism (see 2.2.2).
| Unique Fields | Description |
|---|---|
| fullnode_proof_ref | Reference to fullnode proof object. Needed to verify the correctness of the proof that the node is in full mode |
| is_artificial | Does poll created via artificial node or via regular node |
Expected behavior: Incorrect Fullnode Proof poll will be created.
Signature: Ed25519.
4.18.3 Create custom transaction
Add a new transaction type (thus functionality). Only works when <Beta mode> is activated. This mode allows us to have a more centralized control over the blockchain after its release, for a definite hardcoded period of time. This time period is to address any issues after initial release.
| Unique Fields | Description |
|---|---|
| type | New transaction's unique type |
| expiration | Height limiation of custom transaction existence |
| fields_info | List of new custom transaction fields |
Expected behavior: New custom transaction will be created.
Signature: Pythia Ed25519 collective signature.
4.18.4 Create custom Poll
Custom poll contains basic poll_info (see Table 4.21) and special properties:
| Unique Fields | Description |
|---|---|
| votes_per_wallet | How many times certain account can vote |
| penia_weighted | Does poll voter need to contribute PENIA token |
| price | Price for voting |
| white_list | Who can vote for custom poll |
| min_score | Mininmum score for voter |
| max_score | Maximum score for voter |
Expected behavior: Custom poll will be created.
Signature: Ed25519.
4.18.5 Update config
There are network parameters that are set in the genesis file. They may be updated with this type of poll.
| Unique Fields | Description |
|---|---|
| param | Pair to change: parameter name and it's value |
Expected behavior: Update config poll will be created.
Signature: Ed25519.
4.18.6 Token update
Token's Reward fields can be updated using this transaction.
| Unique Fields | Description |
|---|---|
| token_id | Token to update |
| update_fields | Reaward token fields to update (see Table 4.16) |
Expected behavior: Token Reward poll will be created.
Signature: Ed25519.
4.18.7 Poll Vote
Vote on an existing poll:
| Unique Fields | Description |
|---|---|
| poll_id | Poll's id for voting |
| candidate_index | Who we vote for |
| penia_amount | PENIA token contribution if needed |
| is_artificial | Does vote created via artificial node or via regular node |
Expected behavior: Vote for a candidate in the specific poll will be accepted.
Signature: Ed25519.
4.18.8 Poll Cancel
Creator can cancel their poll.
| Unique Fields | Description |
|---|---|
| poll_id | Poll's id for canceling |
Expected behavior: Poll will be canceled.
Signature: Ed25519.
4.19 Trust Fund Transactions
User can create Trust Funds in the HELO blockchain. First of all, you need to contribute an initial amount of money to it. Then, you must determine the amount and frequency of contributing. If you do it well, you get rewarded in Penia tokens and your credit score goes up. Also, trust fund creator can define at what interval of time and how much can beneficiaries withdraw they tokens from the trust fund. After a specific date, the remaining funds in the trust funds are made available to the contributors based on predetermined ratios on creation.
4.19.1 Add trust fund beneficiary
Add beneficiary to the Trust Fund.
| Unique Fields | Description |
|---|---|
| tf_id | Trust Fund Id |
| acc_id | Account Id which will be a new beneficiary |
Expected behavior: Beneficiary will be added to the Trust Fund.
Signature: Ed25519.
4.19.2 Add withdraw rule for trust fund
Creator can add a withdraw item for some beneficiary in a specific trust fund.
| Unique Fields | Description |
|---|---|
| amount | Percentage which will the beneficiary receive |
| locked_for | Number of blocks starting at the current block where the withdraw is locked. Then, the funds are sent to the beneficiary wallet |
| beneficiary_id | Id of the beneficiaries account |
| tf_id | Trust Fund Id |
Expected behavior: Athena withdraw item added to the trust fund.
Signature: Ed25519.
4.19.3 Create Trust Fund
This functional allows to create new Trust Fund in the HELO blockchain. There can be up to 5 active trust funds per account. Particular trust fund token must support trust funds (see Table 4.15). Beneficiaries have withdraw items (set by Trust Fund creator), which contains the percentage and the number of blocks through which this percentage will be activated (transfered to the beneficiaries account).
Every Trust Fund contains next fields:
| Basic Fields | Description |
|---|---|
| wallet_acc | Trust Fund creator account |
| beneficiaries | Hash table of the ID of the account to his balance in the Trust Fund |
| token_id | Token to add to the trust fund |
| withdraws | List of beneficiary withdraws (see Table 4.33) |
| has_contributions | If true, then the creator is obliged to make donations, otherwise it will be frozen |
| has_stacking_rewards | If true will receive rewards |
| contribution_amount | Minimum amount to contribute |
| contribution_frequency | Number of blocks starting at the current block where a contribution will be made. |
| Basic Fields | Description |
|---|---|
| amount | Amount to withdraw in percentage |
| locked_for | Number of blocks starting at the current block where the withdraw is locked. After that, the funds can be sent to the beneficiary wallet |
| beneficiary_id | Index of the beneficiary in the beneficiary wallets list for whom the withdraw item is for |
Expected behavior: Athena Trust Fund will be created.
Signature: Ed25519.
4.19.4 Make a deposit
Deposit to the Trust Fund. Only Trust Fund creator can do deposits.
| Unique Fields | Description |
|---|---|
| tf_id | Trust Fund Id |
| amount | How many tokens to deposit |
Expected behavior: Tokens have been transferred to a Trust Fund.
Signature: Ed25519.
4.19.5 Withdraw from Trust Fund
Withdraw tokens from Trust Fund.
| Unique Fields | Description |
|---|---|
| tf_id | Trust Fund Id |
| amount | How many tokens to withdraw |
| is_bnf | If it is true then you can't withdraw tokens from Trust Fund balance, but can withdraw from beneficiary balance. If it is false then transaction creator is a Trust Fund creator - can withdraw from Trust Fund balance. |
Expected behavior: Transaction creator withdraw tokens from a Trust Fund.
Signature: Ed25519.
5. Networking
5.1 P2P communication
P2P communication leverages Kademlia and Kadacast (a broadcasting algorithm based on Kademlia) as the basic protocol for message delivery. For more details, see links [kadcast] [kademlia]. There are several stages that a node has to pass in order to become a participant in the network.
Node network entry
Immediately after a node starts, it tries to connect to seeds passed in its arguments. These seeds passed into arguments are considered to be well known endpoints. In the case of a successful connection, there is a process called handshaking, in which the nodes compare their data such as: node implementation version, genesis hash, first lib hash, current times. After a successful handshake, the node starts peer testing process to test if the peer data from the new node is valid. Depending on node validity, it will either operate as a public node or a private node. The new node then sends a request to receive all active peers in the network. During this event? a process called discovering is started. As a response, the node receives a sequence of separate messages containing an active peer. The message containing a peer data of the sender, which is the seed node, is considered to be the last and ends transferring peers.
As soon as active peers data is received, the new node starts updating its connections depends on wether it's a private or public node. In any case, the node will connect to the nearest needed node. As it is defined by the Kademlia protocol structure, as distance between nodes taken a number of the highest bit of result of xor operation between public keys of nodes. In the case of a private node, it chooses only the nearest node as provider by the distance mentioned above in the Kademlia protocol structure. If current node is already the nearest one, so there is no need to reconnect. Nodes separate connections by 8 node in each bucket, containing 32 buckets in total.
Message routing and broadcasting
As mentioned in the previous section, message delivery to given node is based on the Kademlia algorithm. In the case of a private node, intermediate nodes take its provider as the next target for delivery. Then, the provider node sends a direct message to the real target.
On broadcasting a message, node broadcasts all of its public node connections using Kademlia, and then sends messages directly to private node connections. Thus, private nodes route and broadcast messages through their providers.
Updating peers data
As a mechanism of updating peers data, announcing messages with a built in period of time are used. There are two timers involved in updating peers. The first one broadcasts an announce message in order to keep its own peer status as updated in the databases of other network participants. This will be called the announcement timer. The second timer removes a peer if it is not updated and marks the peer data as not updated. This will be called the updating timer. If the announcement timer is T = 30 seconds, the updating timer is 3*T. The node makes the first announcement after the discovery process. This allows network members to connect to the new network participant if needed. On removal of outdated peers, their connections are closed.
In order to satisfy Kademlia, each disconnecting node connects to another node from the same bucket if one exists.
Settings
- P2P default server port is taken 17937, but can be customized by passing a command line argument —p2p.
- The announcement period T is built-in.
5.2 RPC communication
The node provides an RPC endpoint to interact with it. Every RPC session must pass the authentication containing handshaking and challenging parts.
Handshaking
On handshaking, rpc client and node compare the parameters such as chain id - set in the genesis file, version - node implementation id.
Challenge
Immediately after a successful handshake, the node sends the RPC client a challenge request in order to evaluate whether the client has the required private key or not. To do this, the node generates a payload containing a random 32-byte length payload. In order to prove the private key, the client must sign the payload with it and send the challenge response containing the payload. On handling the response, the node verifies the signed result with the given payload. Only after a successful RPC challenge, the client is allowed to send commands. Since the communication is built over web sockets, commands are executed asynchronously by the node.
Settings
- RPC default port is taken 17947, but can be customized by passing a command line argument —rpc.
6. Security
6.1 Countermeasures for Classic Attacks
Sybil attack
A Sybil attack is when someone creates a large number of nodes on a network, perhaps hundreds or thousands on a single machine, in order to get a disproportionate number of votes on networks where each node has an equal vote. According to the PoE implementation, every node has low score, and gradually gains score over time for well behaving. As we have mentioned several times and also seen in the section 1.2, each node should have higher than corresponding threshold to be chosen as an actor. For example, to act as partner a node should have higher than partner_score and etc. So, one can't have an immediate impact on the network by creating a lot of nodes in a short time span. The rules system 2.1 will counter the attack in case of when the attacker creates a lot of nodes and makes every node behave well until they have a high enough score to be enforcers and generators: patterns that go against the principles of Proof of Ethic consensus (like evenly distribution over time) will punished, and eventually blacklisted.
Over 50% attack
When a group of nodes obtains control of more than 50% of a network's blockchain, this is known as a 51 percent assault. Preventing with a 100% certainty this kind of attack is almost impossible, but reducing the chances of a malicious actor to pull it off can definitely be done. Indeed, alongside adding a fee at wallet creation on the network and rules 7-15 from table 2.1 prevent nodes to act as generators/enforcers/partners constantly and often.
The fact that enforcers are, by default, chosen within a specific score range varying in relation to the generated Peterson of each individual node, alongside with the countermeasures enumerated above and those used to counter Sybil attacks, over 50% attack is still possible but extremely hard to execute, and even if a malicious attacker managed to create one, he would be penalized by the predetermined rules really fast. There also the fact that the attacker probably wouldn't be able to compensate fast enough for the constant theoretical income stream of new enforcers in the network.
Replay attack
A replay attack is when someone can use a signed valid information (transaction) that can be processed and repeated numerous times in the network and apply it whenever and however attacker wants. To prevent this behavior, transactions have a NONCE unique field for each user, which must be greater than the previous one on the next transaction sent from this account. So, attacker can't apply transaction second time because it's impossible to change the transaction NONCE field without making the signature invalid.
6.2 DDoS Protection
DDoS (distributed denial-of-service) attack occures when a node floods the incoming traffic with invalid messages, transactions, blocks, etc. The node is protected from that kind of attacks with blocking of IP address if malicious traffic is detected.
When operable, the node monitors a frequency of incoming messages. Although, it monitors a frequency of malicious actions, such as invalid message, invalid signature, invalid block, invalid transaction, etc. If frequence exceeds some threshold, the traffic from that node is considered as DDoS attack, the IP address is blocked. Further, connection queries from that address will be refused.
Monitored actions
- Invalid message was received
- Invalid message signature was detected
- Invalid message content was detected
- Invalid block was received
- Invalid transaction was received
- Too many partner requests
- Too many enforcer request
- Too many block request
- Too many transaction request
- too many blocks with the same height
- Too many collective sign request
- Too many broadcasted blocks
- Too many broadcasted transactions
- Too many announce messages
- Too many incoming messages