A blockchain is a distributed database managed by a peer-to-peer network. The distributed database is also called a ledger which is a continuously growing chain of blocks. Each block contains a number of records and each block is linked to a previous block.

It is extremely difficult to change a record in any given block without the alteration of all subsequent blocks and the collusion of the network.

The first implementation of a blockchain was Bitcoin in 2009 invented by an unknown programmer, or a group of programmers, under the name Satoshi Nakamoto.

After the Bitcoin success many blockchain implementations followed such as Litecoin and Peercoin.

Other blockchain implementations introduces new kind of functionalities such as Ethereum and Dash.

How to setup your own private Ethereum node on macOS

Ethereum is an open-source, public, blockchain-based distributed computing platform featuring smart contract (scripting) functionality. It provides a decentralized virtual machine, the Ethereum Virtual Machine (EVM). This virtual machine can execute Turing-complete scripts using an international network of public nodes and a token called ether. Gas is used to prevent spam on the network and allocate resources proportionally to the incentive offered by the request.

The Ethereum homepage can be found at:
The latest Ethereum documentation can be found at:
The latest Solidity documentation can be found at:
The latest Ethereum source code can be downloaded from:

Operating system used
macOS 10.12 Sierra

Software prerequisites

  1. Setup your own private Ethereum node. Create the following folders:
    Type: mkdir ~/tools
    Type: mkdir ~/tools/ethereum_private_network
    Type: mkdir ~/tools/ethereum_private_network/datadir

  2. I assume you already have Geth installed. Now create 5 accounts, type:
    geth --datadir /Users/robertlie/tools/ethereum_private_network/datadir account new

    You will see:

    WARN [06-19|12:06:31] No etherbase set and no accounts found as default
    Your new account is locked with a password. Please give a password. Do not forget this password.
    Passphrase: mysecret1
    Repeat passphrase: mysecret1
    Address: {de1c70cc1cbcaafdfa6d4593c37cbeb6ed5306d0}

    The folder ~/tools/ethereum_private_network/datadir/keystore now contains a file.
    The file contains the public and private key, the password is not stored!

    An example of such a file:
    UTC--2017-06-19T11-12-59.520967006Z-- de1c70cc1cbcaafdfa6d4593c37cbeb6ed5306d0

    This particular file contains the following:

       "dadedafd8f8da097793f547f917a2a7c86a6 db8a3a69935274f373d62cdee1a0",
       "cipherparams":{"iv": "545424c30e885389ca8ca63f33676b0d"},
       "kdfparams": {
          25a990282b875b397504d30bc19c230 4752bfa1ff0f136e062a9845e29649235"
       "mac":"46fe509470da32a2a20f1fdf4486444fcf 48ed67987c680cd9ca9d9debcf17ad"},

    If you do not specify the "--datadir" parameter a default keystore is created in:

    Repeat this command 4 more times:

    16378b0cdb2719c9bfc8540878d7f116bbed9c22 - password: mysecret2
    c45ae2b9bfae491c79462aaad05fb4b77e7091f2 - password: mysecret3
    549a763482f6c10550c02c865d6b9e7ab0d24eac - password: mysecret4
    6edb33e54bdcb55eb520c7e204a43217b9230966 - password: mysecret5

  3. Create a ~/tools/ethereum_private_network/genesis_private_network.json file.

       "config": {
          "chainId": 987654321,
          "homesteadBlock": 0,
          "eip155Block": 0,
          "eip158Block": 0
       "difficulty": "0x400",
       "gasLimit": "0x8000000",
       "alloc": {}
    • config
      Configuration to describe the chain itself. Specifically the chain ID, the consensus engines to use, as well as the block numbers of any relevant hard forks.

      Identifies the current chain and is used for replay protection. You should set it to a unique value for your private chain.

      Your chain won't be undergoing the switch to Homestead, so leave this as 0.

      Your chain won't be hard-forking for these changes, so leave as 0.

      your chain won't be hard-forking for these changes, so leave as 0.

    • difficulty
      A scalar value corresponding to the difficulty level applied during the nonce discovering of this block. It defines the mining Target, which can be calculated from the previous block’s difficulty level and the timestamp. The higher the difficulty, the statistically more calculations a Miner must perform to discover a valid block. This value is used to control the Block generation time of a Blockchain, keeping the Block generation frequency within a target range. On the test network, we keep this value low to avoid waiting during tests, since the discovery of a valid Block is required to execute a transaction on the Blockchain.

    • gasLimit
      A scalar value equal to the current chain-wide limit of Gas expenditure per block. High in our case to avoid being limited by this threshold during tests. Note: this does not indicate that we should not pay attention to the Gas consumption of our Contracts.

    • alloc
      Allows defining a list of pre-filled wallets. That’s an Ethereum specific functionality to handle the “Ether pre-sale” period. Since we can mine local Ether quickly, we don’t use this option. Coinbase the 160-bit address to which all rewards (in Ether) collected from the successful mining of this block have been transferred. They are a sum of the mining reward itself and the Contract transaction execution refunds. Often named “beneficiary” in the specifications, sometimes “etherbase” in the online documentation. This can be anything in the Genesis Block since the value is set by the setting of the Miner when a new Block is created.

  4. Modify the genesis_private_network.json file.
    • Change the "alloc" parameter.
      You can pre-allocate ethers to your 5 accounts.
      In my example 20 ether (= 0x1158e460913d00000 wei) is allocated for each account.
    • Change the "chainId" parameter.
      Replace 987654321 with your arbitrary chosen number.

    See my modified ~/tools/ethereum_private_network/genesis_private_network.json file.

  5. Create a ~/tools/ethereum_private_network/Makefile file.

  6. Initialize the blockchain from the genesis_private_network.json file.
    Type: cd ~/tools/ethereum_private_network
    Type: make init

    You will see:

    geth --datadir /Users/robertlie/tools/ethereum_private_network/datadir init
    /Users/robertlie/tools/ ethereum_private_network/genesis_private_network.json
    INFO [06-19|13:36:54] Allocated cache and file handles
    database=/Users/robertlie/tools/ ethereum_private_network/datadir/geth/chaindata cache=16 handles=16
    INFO [06-19|13:36:54] Writing custom genesis block INFO [06-19|13:36:54] Successfully wrote genesis state database=chaindata hash=ea3061…dd0ee5
    INFO [06-19|13:36:54] Allocated cache and file handles database=/Users/robertlie/tools/ethereum_private_network/ datadir/geth/lightchaindata cache=16 handles=16
    INFO [06-19|13:36:54] Writing custom genesis block
    INFO [06-19|13:36:54] Successfully wrote genesis state database=lightchaindata hash=ea3061…dd0ee5

  7. The following folders are created:


    The chaindata folder contains the leveldb database files representing the blockchain genesis and subsequent blocks as they are mined and added to the blockchain. This folder will grow in size over time and if deleted or lost, the entire blockchain is gone and will need to be re-initialized.

  8. Modify the ~/tools/ethereum_private_network/Makefile file.
    • Make sure the paths are correct.
    • Make the NETWORK_ID the same as the chain Id in
      ~/tools/ethereum_private_network/genesis_private_network.json file.
    • Modify the ETHERBASE account. This is the account where mining profits are credited. In this example the account 0xc45ae2b9bfae491c79462aaad05fb4b77e7091f2 is used.
    • All loggings are stored in file ~/tools/ethereum_private_network/ethereum.log.

    For more information about the geth command line options, type: geth help

  9. In the Makefile you will see the following lines:

    rm -f $(HOME_DIR)/Library/Ethereum/geth.ipc
    mkdir -p $(HOME_DIR)/Library/Ethereum
    ln -s $(DATA_DIR)/geth.ipc $(HOME_DIR)/Library/Ethereum

    These lines does the following:
    • If the file $(HOME_DIR)/Library/Ethereum/geth.ipc exists, delete it.
    • If the folder $(HOME_DIR)/Library/Ethereum does not exists, create it.
    • Create a symbolic link in folder $(HOME_DIR)/Library/Ethereum pointing to $(DATA_DIR)/geth.ipc

    Tools such as Ethereum Mist communicates with geth using the geth.ipc file.
    This file is created when geth is running.
    By default, tools such as Ethereum Mist EXPECT that geth.ipc is located at $(HOME_DIR)/Library/Ethereum/geth.ipc (for macOS). However my $(DATA_DIR)/geth.ipc is located somewhere else.
    By creating a symbolic link i am fixing this problem.

    Why am i doing this? Because i have setup different geth nodes on my laptop: one for a private ethereum node, one for Rinkeby testnet and one for Ropsten testnet.

  10. Start mining.
    Type: cd ~/tools/ethereum_private_network
    Type: make mine

    You will see:

    Welcome to the Geth JavaScript console!

    instance: Geth/v1.6.5-stable-cf87713d/darwin-amd64/go1.8.3
    coinbase: 0xc45ae2b9bfae491c79462aaad05fb4b77e7091f2
    at block: 0 (Thu, 01 Jan 1970 01:00:00 CET)
    datadir: /Users/robertlie/tools/ethereum_private_network/--nodiscover
    modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0


  11. You can create another Geth JavaScript console by opening a new terminal and typing the command:
    geth attach

    This works if ~/Library/Ethereum/geth.ipc exists (for macOS), if not type:
    geth attach /your_path_to/geth.ipc

  12. The ~/tools/ethereum_private_network/ethereum.log shows the following information:

    INFO [06-19|14:43:22] Starting peer-to-peer node instance=Geth/
    INFO [06-19|14:43:22] Allocated cache and file handles database= /Users/robertlie/tools/ethereum_private_network/ datadir/geth/chaindata cache=128 handles=1024
    WARN [06-19|14:43:22] Upgrading chain database to use sequential keys
    INFO [06-19|14:43:22] Initialised chain configuration config="{ChainID: 987654321 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Metropolis: <nil> Engine: unknown}"
    INFO [06-19|14:43:22] Disk storage enabled for ethash caches dir=/Users/robertlie/tools/ ethereum_private_network/datadir/geth/ethash count=3
    INFO [06-19|14:43:22] Disk storage enabled for ethash DAGs dir=/Users/robertlie/.ethash count=2
    INFO [06-19|14:43:22] Database conversion successful
    WARN [06-19|14:43:22] Upgrading db log bloom bins
    INFO [06-19|14:43:22] Bloom-bin upgrade completed elapsed=69.382µs
    INFO [06-19|14:43:22] Initialising Ethereum protocol versions="[63 62]" network=4321
    INFO [06-19|14:43:22] Loaded most recent local header number=0 hash=ea3061…dd0ee5 td=200000000
    INFO [06-19|14:43:22] Loaded most recent local full block number=0 hash=ea3061…dd0ee5 td=200000000
    INFO [06-19|14:43:22] Loaded most recent local fast block number=0 hash=ea3061…dd0ee5 td=200000000
    INFO [06-19|14:43:22] Starting P2P networking
    INFO [06-19|14:43:22] RLPx listener up self="enode://30742b167c31c1d5e796cd9499464a33bcd9da272f435b2dc 6fa56a95cc6750b50e633a96b13e7a3323e08011d23e26eeeaac6632073495bc [email protected][::]:30303?discport=0"
    INFO [06-19|14:43:22] IPC endpoint opened: /Users/robertlie/tools/ethereum_private_network/datadir/geth.ipc
    INFO [06-19|14:43:22] HTTP endpoint opened: http://localhost:8545
    INFO [06-19|14:43:22] Starting mining operation
    INFO [06-19|14:43:22] Commit new mining work number=1 txs=0 uncles=0 elapsed=125.355µs
    INFO [06-19|15:13:06] Successfully sealed new block number=1 hash=6457eb…625a7d
    INFO [06-19|15:13:06] 🔨 mined potential block number=1 hash=6457eb…625a7d
    INFO [06-19|15:13:06] Commit new mining work number=2 txs=0 uncles=0 elapsed=250.727µs

  13. You will see the Ethereum's Javascript console prompt. You can enter the following commands:

    • eth.accounts
      List all accounts

      The first account is eth.accounts[0], the second is eth.accounts[1] etc.

    • personal.unlockAccount(address, "password")
      Unlock accounts (one at a time)

    • web3.fromWei(eth.getBalance(eth.coinbase), "ether")
      Check the etherbase account balance.

    • web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
      Show balance of an account.

    • personal.newAccount("passwd")
      Create a new password protected account.

    • personal.unlockAccount(addr, "passwd", duration)
      Unlock the account with the given address, password and an optional duration (in seconds). If password is not given you will be prompted for it.

      For example: personal.unlockAccount(eth.coinbase, "passwd", 300);

    • txpool.status
      Number of pending/queued transactions.

    • admin.nodeInfo
      Information on the node.

    • admin.peers
      Show an array of objects with information about connected peers.

    More information about the Ethereum's Javascript console and other helpfull commands, see:

  14. To stop mining AND close the console, type: exit

    If you only want to stop mining, type: miner.stop()
    To start mining again, type: miner.start()