Skip to content
Alex Dovzhanyn edited this page Feb 3, 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/
│   ├── apps/
│   │     ├── miner/
│   │     ├── wallet/
│   ├── config/
│   ├── core/
│   └── .chaindata/

Core

The core/ directory contains all of the logic for the blockchain. This stores the modules which define the way Blocks, Transactions, Ledgers, and other important parts of the UltraDark blockchain work. Many other parts of the codebase use the modules within this directory.

Miner

The miner/ directory contains all the files needed in order to run a miner on your machine. This folder contains defines a mix task within it, which is where the command mix miner comes from. This application inherits most of its functionality from the modules in core/.

Wallet

The wallet/ directory contains the wallet functionality, which allows for the creation of transactions (among other things).

Chaindata

The .chaindata/ directory is a hidden directory within the project root. This directory is the storage directory of LevelDB, which is the key/value store we use to manage the blockchain. Every block in the blockchain is stored in this directory, in binary format.

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 apps/miner/lib/mix/tasks/miner.ex calls the Miner.initialize function, which is defined in apps/miner/lib/miner.ex.
  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 sha256 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 sha256 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. This is then passed back into the main function, and the same process happens in order to create the next block.
Clone this wiki locally