/jeffCoin

My cryptocurrency

Primary LanguageGoMIT LicenseMIT

jeffCoin

*** THE REPO IS UNDER CONSTRUCTION - CHECK BACK SOON ***

Go Report Card GoDoc Maintainability Issue Count License

A cryptocurrency (transaction based data) built on decentralized multi-node P2P open Network using a sha256 Proof of Work (PoW) blockchain with a REST JSON API and a TCP Server to communicate between the Nodes over IP.

Or more simply, a distributed decentralized public ledger.

To dive right in, head down to RUN.

Table of Contents,

This project was built from some of my other projects,

Documentation and reference,

GitHub Webpage

IMPORTANT

Your private keys are kept in /wallet. The .gitignore file does ignore them, but just be aware were they live. There are a few mock keys there used for testing.

PREREQUISITES

go get -v -u github.com/btcsuite/btcutil/base58
go get -v -u golang.org/x/crypto/ripemd160
go get -u -v github.com/gorilla/mux
go get -u -v github.com/sirupsen/logrus
go get -u -v github.com/pkg/errors

OVERVIEW

jeffCoin (JEFC) is my interpretation of a transaction based (ledger) using a blockchain. This is a work in progress I feel can be used as a foundation to build bigger and better things.

Coins (a.k.a jeffCoins) are minted as follows,

  • A grand total of 1,000,000 jeffCoins
  • The blockchain will not store jeffCoins but addies which are 1/1000 of a jeffCoin (.001 JEFC).
  • The founders wallet will start with 100,000 jeffCoins (100,000,000 addies) (10% of all jeffCoins)
  • Rewards 1 jeffCoin (1000 addies) every 10 minutes (144 jeffCoins/day or 52,560 jeffCoins/year)
  • Will take 17.12 years to mint all the jeffCoins (900,000/52,560 = 17.12)

jeffCoin uses the following technology,

  • Written in golang
  • Implements a blockchain using a sha256 hash
  • A decentralized multi-node P2P architecture maintaining a Network of Nodes
  • A Webserver with both a GUI and a REST API
  • A TCP Server for inter-node communication
  • ECDSA Private & Public Key generation
  • Creates a jeffCoin Address from the ECDSA Public Key (Just like bitcoin)
  • ECDSA Digital Signature Verification
  • Mining uses Proof of Work (PoW)
  • Transaction as stored using the unspent transaction output model

What jeffCoin does not have,

  • No database, so if the entire Network dies, the chain dies
  • Rigorous testing of all corner cases

The following illustration shows how the code is broken up into five main areas,

IMAGE - jeffCoin-architecture - IMAGE

1. BLOCKCHAIN

The blockchain section is the heart of the entire design. It will keep the transactions secure. A transaction is a transfer of value (jeffCoins) between jeffCoin Addresses. Like bitcoin, the value (jeffCoins) is contained in the ledger. The wallets just hold the public/private keys to request a transaction.

This blockchain section has two main parts, the blockchain and the transactions (the data on the blockchain).

1.1 BLOCKCHAIN

This blockchain is built from my single-node-blockchain-with-REST.

BLOCKCHAIN-DATASTRUCTURES

A block in the blockchain is the following go struct,

type blockStruct struct {
    BlockID      int64               `json:"blockID"`
    Timestamp    string              `json:"timestamp"`
    Transactions []transactionStruct `json:"transactions"`
    Hash         string              `json:"hash"`
    PrevHash     string              `json:"prevhash"`
    Difficulty   int                 `json:"difficulty"`
    Nonce        string              `json:"nonce"`
}

The states of a block are,

  • pendingBlock Receiving transactions and not part of blockchain
  • lockedBlock To be mined and added to the blockchain
  • Part of Chain Already in the blockchain

This illustration may help,

IMAGE - pendingBlock-lockedBlock-and-blockchain-flow - IMAGE

BLOCKCHAIN-INTERFACE FUNCTIONS

  • BLOCKCHAIN
    • GetBlockchain() Gets the blockchain
    • GenesisBlockchain() Creates the blockchain
    • RequestBlockchain() Requests the blockchain and the pendingBlock from a Network Node
      • SEND-BLOCKCHAIN Request
  • BLOCK
    • GetBlock() Gets a block (via Index number) from the blockchain
  • LOCKED BLOCK
    • GetLockedBlock() Gets the lockedBlock
    • AppendLockedBlock() Appends the lockedBlock to the blockchain
  • PENDING BLOCK
    • GetPendingBlock() Gets the pendingBlock
    • ResetPendingBlock() Resets the pendingBlock
    • AddTransactionToPendingBlock() Adds a transaction to the pendingBlock and makes change
    • LockPendingBlock() Moves the pendingBlock to the lockedBlock
  • JEFFCOINS
    • GetAddressBalance() Gets the jeffCoin Address balance
  • TRANSACTIONS
    • ProcessTxRequestMessage() Request to transfer jeffCoins to a jeffCoin Address

GUTS FUNCTIONS

  • BLOCKCHAIN
    • getBlockchain() Gets the blockchain
    • loadBlockchain() Loads the entire blockchain
    • replaceBlockchain() Replaces blockchain with the longer one
  • BLOCK
    • getBlock() Gets a block in the blockchain
    • calculateBlockHash() Calculates SHA256 hash on a block
    • isBlockValid() Checks if block is valid
  • LOCKED BLOCK
    • getLockedBlock() Gets the lockedBlock
    • appendLockedBlock() Appends the lockedBlock to the blockchain
  • PENDING BLOCK
    • getPendingBlock() Gets the pendingBlock
    • loadPendingBlock() Loads the pendingBlock
    • resetPendingBlock() Resets the pendingBlock
    • addTransactionToPendingBlock() Adds a transaction to the pendingBlock and makes change
    • lockPendingBlock() Moves the pendingBlock to the lockedBlock
  • JEFFCOINS
    • getAddressBalance() Gets the jeffCoin Address balance

1.2 TRANSACTIONS

Transaction are at the heart of jeffCoin, allowing the transfer of value (jeffCoins) from one jeffCoin Address to another. A transaction request comes from the wallet which holds the private key. All transaction requests are broadcast to the entire Network before it is validated. Each Node does its own Proof of Work (PoW).

The transactions are stored in the block using the unspent transaction output model. Basically a chain of ledger transactions.

This was built using my ecdsa signature verification from ecdsa-digital-signature and the transaction ledger was built from my bitcoin-ledger.

BLOCKCHAIN-DATASTRUCTURES

A transaction for a block is the following go struct,

type transactionStruct struct {
    TxID    int64           `json:"txID"`
    Inputs  []inputsStruct  `json:"inputs"`
    Outputs []outputsStruct `json:"outputs"`
}

type inputsStruct struct {
    RefTxID   int64  `json:"refTxID"`
    InPubKey  string `json:"inPubKey"`
    Signature string `json:"signature"`
}

type outputsStruct struct {
    OutPubKey string `json:"outPubKey"`
    Value     int64  `json:"value"`
}

And the transaction request message is,

type txRequestMessageSignedStruct struct {
    TxRequestMessage txRequestMessageStruct `json:"txRequestMessage"`
    Signature        string                 `json:"signature"`
}

type txRequestMessageStruct struct {
    SourceAddress string              `json:"sourceAddress"`
    Destinations  []destinationStruct `json:"destinations"`
}

type destinationStruct struct {
    DestinationAddress string `json:"destinationAddress"`
    Value              int64  `json:"value"`
}

TRANSACTION FUNCTIONS

  • TRANSACTIONS
    • processTxRequestMessage() Request to transfer jeffCoins to a jeffCoin Address
  • SIGNATURE
    • verifySignature() Verifies a ECDSA Digital Signature
  • UNSPENT OUTPUTS
    • pickUnspentOutputs() Pick the Unspent Outputs to use and provide change

This illustration shows transaction requests, verification for that request and addition onto the pendingBlock. A transaction is never valid until the transaction is added onto the blockchain.

IMAGE - transaction-request-message-flow - IMAGE

2. MINER

The miner section has the following features,

  • Miner automatically tells blockchain-interface to place pendingBlock into lockedBlock
  • Performs the mining (poW) on the lockedBlocked
  • Difficulty is how many zero are needed at the beginning of the hash
  • When block is solved, broadcast block to entire Network to check for consensus

MINER-DATASTRUCTURES

The proof of work structure is,

type tbd struct {
    tbd
}

MINER-INTERFACE FUNCTIONS

  • MINING
    • tbd() tbd

GUTS FUNCTIONS

  • MINING
    • tbd() tbd

IMAGE - mining-control-and-consensus-flow - IMAGE

3. ROUTINGNODE

The Routingnode section has two main parts, the nodeList and the ability to handle the Node TCP Requests (TCP Server). The nodeList keeps a listing of all Nodes in the Network. The TCP Server handles requests from other Nodes.

The routingnode is built from my simple-tcp-ip-server.

3.1 NODELIST

ROUTINGNODE-DATASTRUCTURES

A Node in the nodeList is the following go struct,

type nodeStruct struct {
    Index       int    `json:"index"`
    Status      string `json:"status"`
    Timestamp   string `json:"timestamp"`
    NodeName    string `json:"nodename"`
    ToolVersion string `json:"toolversion"`
    IP          string `json:"ip"`
    HTTPPort    string `json:"httpport"`
    TCPPort     string `json:"tcpport"`
}

ROUTINGNODE-INTERFACE FUNCTIONS

  • NODELIST
    • GetNodeList() Gets the nodeList
    • GenesisNodeList() Creates the nodeList
    • RequestsNodeList() Requests the nodeList from a Network Node
      • SEND-NODELIST Request
  • NODE
    • GetNode() Gets a Node (via Index number) from the nodeList
    • AppendNewNode() Appends a new Node to the nodeList
  • THIS NODE
    • GetThisNode() Gets thisNode
    • LoadThisNode() Loads thisNode
    • AppendThisNode() Appends thisNode to the nodeList
    • BroadcastThisNode() Broadcasts thisNode to the Network
      • BROADCAST-ADD-NEW-NODE Request

GUTS FUNCTIONS

  • NODELIST
    • getNodeList() Gets the nodeList
    • loadNodeList() Loads the entire nodeList
  • NODE
    • getNode() Gets a Node in the nodeList
    • appendNewNode() Appends a new Node to the nodeList
  • THIS NODE
    • getThisNode() Gets thisNode
    • loadThisNode() Loads thisNode
    • appendThisNode() Appends thisNode to the nodeList
    • checkIfThisNodeinNodeList() Check if thisNode is already in the nodeList

3.2 TCP REQUESTS & HANDLERS

Incoming requests to the TCP server from other Nodes or TCP connection.

An illustration of client-server handshakes,

IMAGE - tcp-client-server-handshake - IMAGE

HANDLERS

  • FROM BLOCKCHAIN I/F
    • handleSendBlockchain() SEND-BLOCKCHAIN (SBC)- Sends the blockchain and pendingBlock to another Node
  • FROM ROUTINGNODE I/F
    • handleBroadcastAddNewNode() BROADCAST-ADD-NEW-NODE (BANN) - Adds a Node to the nodeList
    • handleSendNodeList() SEND-NODELIST (SNL) - Sends the nodeList to another Node
    • handleBroadcastVerifiedBlock() BROADCAST-VERIFIED-BLOCK (BVB) - A Node verified the next block, get block and verify
    • handleBroadcastConsensus() BROADCAST-CONSENSUS (BC) - 51% Consensus reached, get block to add to blockchain
    • handleBroadcastTransactionRequest() BROADCAST-TRANSACTION-REQUEST (BTR) - Request from a Node to transfer jeffCoins to a jeffCoin Address
  • FROM WALLET I/F
    • handleSendAddressBalance() SEND-ADDRESS-BALANCE (SAB) - Sends the jeffCoin balance for a jeffCoin Address
    • handleTransactionRequest() TRANSACTION-REQUEST (TR) - Request from Wallet to transfer jeffCoins to a jeffCoin Address
  • EOF
    • EOF Close Connection

4. WALLET

The wallet section holds the Public Key, the Private Key and the jeffCoin Address. Like bitcoin, wallets do not have or hold any jeffCoins. The jeffCoins are in the blockchain transactions (ledger).

Generating keys and creating the jeffCoin address is built from my create-bitcoin-address-from-ecdsa-publickey.

Your wallet will be saved in the following file based on your nodename, /wallet/{nodename}-wallet.json.

WALLET-DATASTRUCTURES

A wallet has the following go struct,

type walletStruct struct {
    PrivateKeyHex   string `json:"privateKeyHex"`
    PublicKeyHex    string `json:"publicKeyHex"`
    JeffCoinAddress string `json:"jeffCoinAddress"`
}

WALLET-INTERFACE FUNCTIONS

  • WALLET
    • GetWallet() Gets the wallet
    • GenesisWallet() Creates the wallet and writes to file (Keys and jeffCoin Address)
    • ReadWalletFile() Reads the wallet from a file
  • KEYS
    • EncodeKeys() Encodes privateKeyRaw & publicKeyRaw to privateKeyHex & publicKeyHex
    • DecodeKeys() Decodes privateKeyHex & publicKeyHex to privateKeyRaw & publicKeyRaw
  • JEFFCOINS
    • RequestAddressBalance() Requests the jeffCoin balance for a jeffCoin Address
      • SEND-ADDRESS-BALANCE Request
    • TransactionRequest() Request to transfer jeffCoins to a jeffCoin Address
      • TRANSACTION-REQUEST Request
  • SIGNATURE
    • CreateSignature() Creates a ECDSA Digital Signature

GUTS FUNCTIONS

  • WALLET
    • getWallet() Gets the wallet
    • makeWallet() Creates the wallet and writes to file (Keys and jeffCoin Address)
    • readWalletFile() Reads the wallet from a file
  • KEYS
    • generateECDSASKeys() Generate privateKeyHex and publicKeyHex
    • encodeKeys() Encodes privateKeyRaw & publicKeyRaw to privateKeyHex & publicKeyHex
    • decodeKeys() Decodes privateKeyHex & publicKeyHex to privateKeyRaw & publicKeyRaw
  • JEFFCOIN ADDRESS
    • generateJeffCoinAddress() Creates a jeffCoin Address
    • hashPublicKey() Hashes publicKeyHex
    • checksumKeyHash() Checksums verPublicKeyHash
    • encodeKeyHash() Encodes verPublicKeyHash & checkSum
  • SIGNATURE
    • createSignature() Creates a ECDSA Digital Signature

5. WEBSERVER

The webserver section has two main parts, the GUI and the REST API.

This webserver is built from my simple-webserver-with-REST.

5.1 GUI

Currently, there is the main page that also lists the available APIs.

The screen should look similar to the following,

IMAGE - webpage - IMAGE

5.2 REST API

API COMMANDS

  • BLOCKCHAIN
    • /showBlockchain
    • /showBlock/{blockID}
  • PENDING AND LOCKED BLOCK
    • /showpendingblock
    • /showlockedblock
  • NODELIST
    • /shownodelist
    • /shownode/{nodeID}
    • /showthisnode
  • WALLET (THIS NODE)
    • /showwallet
    • /showjeffcoinaddress
    • /showbalance
    • /transactionrequest/{destinationaddress1,destinationaddress2,...}/{value1,value2,...}
  • WALLET (OTHER)
    • /showaddressbalance/{jeffcoinaddress}

RUN

If this is you first time running, you need to create the first Node (Genesis Node). You only do this once. You can set the log level (info, debug, trace) to cut down on the amount of logging.

GENESIS NODE

go run jeffCoin.go \
       -loglevel debug \
       -genesis \
       -nodename Founders \
       -ip 127.0.0.1 \
       -httpport 2000 \
       -tcpport 3000

This will created the first Node (the Founders node) in the Network. It will also create a wallet and save the credentials in /wallet. But having one node is boring so create more.

ADDING NEW NODES

To hook up to the Network. You need the IP of any working Network Node. If you have the above running on 127.0.0.1:3000, adding a second Node "Jeff" in your network could look like,

go run jeffCoin.go \
       -loglevel debug \
       -nodename Jeff \
       -ip 127.0.0.1 \
       -httpport 2001 \
       -tcpport 3001 \
       -netip 127.0.0.1 \
       -netport 3000

Might as well add a third Node,

go run jeffCoin.go \
       -loglevel debug \
       -nodename Matt \
       -ip 127.0.0.1 \
       -httpport 2002 \
       -tcpport 3002 \
       -netip 127.0.0.1 \
       -netport 3000

Each node has it's own wallet, so now you can send jeffCoins/Value. To do this, use the webserver and API interface.

WEBSERVER & REST API

The GUI for the three nodes you just created are,

127.0.0.1:2000 / 127.0.0.1:2001 / 127.0.0.1:2002

The main page will list the various API commands. For example, to show a particular block,

127.0.0.1:2000/showblock/0

SWITCHES (REFERENCE)

-h prints the following,

  • -gce Is this Node on GCE
  • -genesis Create your first Node
  • -httpport string Node Web Port (default "2001")
  • -ip string Node IP (default "127.0.0.1")
  • -loglevel string LogLevel (info, debug or trace) (default "info")
  • -netip string Network IP (default "127.0.0.1")
  • -netport string Network TCP Port (default "3000")
  • -nodename string Node Name (default "Jeff")
  • -tcpport string Node TCP Port (default "3001")
  • -test Loads the blockchain with test data (SEE BELOW)
  • -v prints current version

CONNECT USING TCP (OPTIONAL)

You can also bypass the REST API and just open a connection to the TCP server itself,

netcat -q -1 127.0.0.1 3000

And request commands such as,

--- Waiting for command: SBC, BANN, SNL, BVB, BC, BTR, SAB, TR, EOF
SNL
[...nodeList...]
thank you

Notice you will need to handshake it with a thank you at the end.

There is a complete list of commands up above in TCP REQUESTS & HANDLERS.

TEST MOCK TRANSACTIONS (OPTIONAL)

If you add the -test switch you will run some mock transactions from mock wallets. Those wallets are located in /wallets and just used for testing.

You must use the MockFounders nodename,

go run jeffCoin.go \
       -loglevel debug \
       -genesis \
       -nodename MockFounders \
       -ip 127.0.0.1 \
       -httpport 2000 \
       -tcpport 3000 \
       -test

These transactions are the same I used in my bitcoin-ledger example.

So your blockchain and pendingBlock should look similar to blockchain-output.txt.

And the balances in the blockchain should be,

The balance for MockFounders PubKey (Address) is 99657000
The balance for MockJeffs PubKey (Address) is 42500
The balance for MockMatts PubKey (Address) is 265000
The balance for MockJills PubKey (Address) is 35000
The balance for MockCoinVaults PubKey (Address) is 500

Remember, the pendingBlock is pending, so it's not part of this calculation. Transaction do not have value if they are not part of the blockchain.

RUN ON GOOGLE COMPUTE ENGINE (GCE) (OPTIONAL)

Make sure your create a firewall rule and have your instance use it as a network tag,

gcloud compute firewall-rules create jeffs-firewall-settings-rule \
    --action allow \
    --rules tcp:1234,tcp:3334 \
    --priority 1000 \
    --source-ranges 0.0.0.0/0 \
    --target-tags "jeffs-firewall-settings" \
    --description "Jeffs firewall rules"

The IP 0.0.0.0 gets forwarded to your external IP, hence I added a -gce switch to deal with this,

go run jeffCoin.go \
       -gce \
       -loglevel debug \
       -genesis \
       -nodename Founders \
       -ip 35.203.189.193 \
       -httpport 1234 \
       -tcpport 3334

Add another node (not at gce) with,

go run jeffCoin.go \
       -loglevel debug \
       -nodename Jeff \
       -ip 192.168.20.100 \
       -httpport 1235 \
       -tcpport 3335 \
       -netip 35.203.189.193 \
       -netport 3334

I have a gce build example here.

UPDATE GITHUB WEBPAGE USING CONCOURSE (OPTIONAL)

For fun, I use concourse to update jeffCoin GitHub Webpage and alert me of the changes via repo status and slack.

A pipeline file pipeline.yml shows the entire ci flow. Visually, it looks like,

IMAGE - jeffCoin concourse ci pipeline - IMAGE

The jobs and tasks are,

The concourse resources types are,

  • jeffCoin uses a resource type docker-image to PULL a repo from github.
  • resource-slack-alert uses a resource type docker image that will notify slack on your progress.
  • resource-repo-status uses a resource type docker image that will update your git status for that particular commit.

For more information on using concourse for continuous integration, refer to my cheat sheet on concourse.