Skip to content

block.ex

Alex Dovzhanyn edited this page Feb 18, 2018 · 3 revisions

This file is responsible for storing all the functions related to blocks.

Attributes

Index

The index is an integer value that determines the position of the block within the chain. This is similar to how a database has an "id" field, which it uses to index the values in it. The index of a block must be exactly 1 higher than the block before it. It's important to note that our chain is reverse sorted, due to how Elixir handles list modification; it is exponentially more computationally intensive to add an item to the end of the list, while it is very easy to add to the beginning of the list. Because of this, the first block in the chain will always be the latest, and the last block in the chain will always be the genesis block. An index is not necessarily unique. Because an index is just the representation of the location of the block within the chain, when 2 miners mine a block at the same time, if a fork is successfully created, both block indexes will be the same.

Hash

The hash of a block is a SHA3 representation of the block header. The block header is not stored in the block, but is made up of items in the block. The block header is the concatenated version of the block index, the hash of the block that came before it (previous_hash), the timestamp of the block, the nonce, and the merkle root of all transactions within the block.

Previous Hash

The previous_hash of a block refers to the hash of the block that came directly before it. This is what links blocks together; if a block earlier in the chain changes, then its hash will also change, meaning all blocks that came after it will now have different hashes (since the previous_hash is used to calculate the hash).

Difficulty

This is a float representing the difficulty that was used to mine the block. The higher the difficulty, the harder it is to mine the block (more PoW). The difficulty scales as the network hashrate increases/decreases. This difficulty is used to calculate the target number of the block hash. When a miner mines the block, they need the number represented by the hash to be lower than the target.

For example, the (minimum) difficulty 0 would mean that the target number is 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, which is 115792089237316195423570985008687907853269984665640564039457584007913129639935. The miner would need to generate a hash that, when converted from base 16 to base 10, would be lower than that number. As the difficulty increases, the target number becomes proportionally lower, making it harder to generate a hash that is lower than the target.

Nonce

The nonce is an integer that the miner increments every time they attempt to hash a block. Since hashing the block header (index, previous_hash, timestamp, merkle_root) creates the same hash no matter how many times you hash, the process of mining a block would never work, you would always be producing the same hash. The nonce is added to the block header before it is hashed in order to make it different on each iteration, which means you generate a different hash on every iteration.

Timestamp

A utc representation of the time when the block was generated (right before it starts getting mined)

Merkle Root

The merkle root is a hexadecimal string representing all of the transactions withing the block. Because the SHA3 hashing algorithm takes longer to hash when representing a larger set of data, miners would be discouraged from including transactions into blocks if the block header consisted of all transactions. Instead, we find the merkle root of the ids of the transactions within the block before we start mining and use that, so hashing isn't slowed down -- no matter how many transactions are included in the block, the size of the merkle root is the same.

Transactions

This is a list containing every transaction in the block

Functions

initialize/0

This function is only ever called the on the first node on the network, and it generates a statically defined genesis block, which is needed as a base of the blockchain, since all blocks need a previous_hash. This block is a special one, and never needs to be validated.

initialize/1

Takes a block as an argument, and returns a new block based off of it. Essentially, the block passed into this function will be the previous block. We use the previous block in as a reference, from which we generate a new, empty block that has an index that is 1 higher than the latest block in the chain, and has the previous_hash set to the hash of the block that was passed in. This is the function used to create new, empty blocks.

mine/1

Takes in a block that has been generated by initialize/1 and generates a hash for it, based off the blocks difficulty. The generated hash must be lower than the target for this function to return. It'll keep calling itself recursively until this condition is met.

hash_beat_target?/1

Uses the difficulty of the block to determine if the hash generated by the mine/1 function is lower than the target.

calculate_target/1

Takes in a difficulty and returns a target integer.

calculate_block_reward/1

Uses a block index to calculate the reward for mining the block. Every 200,000 blocks, the reward is cut in half. The block reward starts at 100, meaning that the maximum number of shades to ever exist will be ~40,000,000.

total_block_fees/1

Takes an array of transactions and finds the total fee (in shades) for all transactions within the block, combined.