Skip to content
Alex Dovzhanyn edited this page Feb 20, 2018 · 6 revisions

The purpose of this wiki is to guide those who are contributors/looking to understand the codebase through our architecture and folder structure. The general structure of the project is listed below, but there are pages in this wiki for each of the major components as well.

Folder Structure

Let's cover the folders and locations of important bits of code, along with a small description of what they do. A basic outline of the folder structure is as follows:

├── ultradark_core/
│   ├── lib/
│   │     ├── block.ex
│   │     ├── blockchain.ex
│   │     ├── keypair.ex
│   │     ├── ledger.ex
│   │     ├── store.ex
│   │     ├── transaction.ex
│   │     ├── utilities.ex
│   │     ├── utxo_store.ex
│   │     ├── validator.ex

Block

Responsible for functions that create / mine blocks

Blockchain

An interface for interacting with the blockchain

Keypair

Create keys and signatures, and verify signatures

Ledger

Functions for storing and retrieving blocks from Leveldb

Store

Wrapper functions shared by ledger.ex and utxo_store.ex

Transactions

Create transactions

Utilities

Functions used by multiple different modules for multiple purposes

UTXO Store

Functions to interface with the Leveldb instance that stores utxo data

Validator

Functions that implement the consensus algorithm

Basic Application Flow

Let's look at a high-level, step-by-step description of how the blockchain works. Assuming you run mix miner, what happens is:

  1. A pre-defined mix task in the miner program calls the Miner.initialize function.
  2. This function initialized LevelDB (by calling Ledger.initialize), which will create a .chaindata directory in the root of the project. This then calls Blockchain.initialize, which either generates a genesis block, or retrieves the existing chain from LevelDB.
  3. Then, the main function is called. This function takes the first block in the chain (our chain is reverse sorted, meaning the latest blocks will be in the front of the list) and uses that to create a new block. This new block will reference the previous blocks hash as its prev_hash, and it will have an index that is 1 higher than the previous block.
  4. Once the new block is generated, The coinbase is generated for this block. A block must have a coinbase to be considered valid.
  5. This coinbase is then added to the list of transactions within the block. The coinbase must be the first transaction in the block for the block to be considered valid. The coinbase is the payment to the miner, so the amount of the coinbase output will be the sum of all the transaction fees within the block plus the block reward.
  6. This block is then taken and passed to the Block.mine function, which constructs a block header based on a few properties of the block, and returns a base16 encoded sha3 digest of this block header. This is the block's hash.
  7. The Block.mine function will continue to loop until the hash of the block is lower than the target. The target is calculated based on the difficulty of the block. Since each sha3 hash represents a 256 bit number, the numerical value represented by the hash is compared to the target. If it is lower, the valid hash has been found!
  8. Once the hash has been found, the block goes through a series of validations, and if the block is deemed valid, it is added to the chain and stored in LevelDB. The transactions of this new block are parsed and the UTXO store is updated based on the inputs/outputs of each transaction. This is then passed back into the main function, and the same process happens in order to create the next block.