Blockchain Nanodegree Notes 20181106

Term 1 S3 Lesson5: Private Blockchains

Lesson Introduction

Public and Private Blockchains

Compare and contrast a public blockchain vs a private blockchain and discuss methods for cross-chain functionality.

Building a Simple Private Blockchain

Build from scratch a simple private blockchain that creates new blocks, store data in blocks, and secure blocks with a digital signature using a one-way hash.

To Build a Simple Private Blockchain, we’ll work through 6 different parts that, once completed, will have you up and running with the core ideas behind building a simple private blockchain.

Part 1: Block Data Model

Part 2: Create New Blocks

Part 3: Store Blocks

Part 4: Linking Blocks

Part 5: Block Height and Timestamp

Part 6: LevelDB to Persist Data

Complementary learning resources

  • JavaScript Promises
  • ES6 - JavaScript Improved

Public and Private Blockchains

OP_RETURN

stores up to 40 bytes

  • SHA256 Hash =256 bits
  • Binary encoding = 8 bits per byte
  • 256bits/(8bits/byte) = 32 bytes

Block Data Model

#npm init

//Block data model
{
   "hash": "",
   "height": 0,
   "body": [
   ],
   "time": 0,
   "previousblockhash": ""
 }

Create and Store Blocks

#touch simpleChain.js

#node

class Block{
  	constructor(data){
    //Block data model
   	this.hash = "",
   	this.height = 0,
   	this.body = data,
   	this.time = 0,
   	this.previousblockhash = ""
    }
}

class Blockchain{
    constructor(){
      // new chain array
      this.chain = [];
  }

  // addBlock method
  addBlock(newBlock){
     this.chain.push(newBlock);
  }
}

> let blockchain = new Blockchain()

> blockchain.addBlocknode

(new Block('test data'))

> blockchain.chain

Link Blocks

#npm install crypto-js -save

In simpleChain.js,

  • Configured crypto-js library
  • In Blockchain class, modified constructor to included new genesis block
  • Modified addblock function to include generation of our block hash.
/* ===== SHA256 with Crypto-js ===================================
|  Learn more: Crypto-js: https://github.com/brix/crypto-js      |
|  =============================================================*/

const SHA256 = require('crypto-js/sha256');

/* ===== Block Class ===================================
|  Class with a constructor for block data model       |
|  ====================================================*/

class Block {
  constructor(data){
    this.height = '';
    this.timeStamp = '';
    this.data = data;
    this.previousHash = '0x';
    this.hash = '';
  }
}

/* ===== Blockchain ===================================
|  Class with a constructor for blockchain data model  |
|  with functions to support:                          |
|     - createGenesisBlock()                           |
|     - getLatestBlock()                               |
|     - addBlock()                                     |
|     - getBlock()                                     |
|     - validateBlock()                                |
|     - validateChain()                                |
|  ====================================================*/

class Blockchain{
    constructor(){
      // new chain array
      this.chain = [];
      // add first genesis block
      this.addBlock(this.createGenesisBlock());
   }

  createGenesisBlock(){
    return new Block("First block in the chain - Genesis block");
  }

// addBlock method
  addBlock(newBlock){
    if (this.chain.length>0) {
      // previous block hash
      newBlock.previousHash = this.chain[this.chain.length-1].hash;
    }
    // SHA256 requires a string of data
    newBlock.hash = SHA256(JSON.stringify(newBlock)).toString();
    // add block to chain
    this.chain.push(newBlock);
  }
}

Testing:

> let blockchain = new Blockchain()

> blockchain.addBlock(new Block('test'))

> blockchain.chain

Block Height and Timestamp

/* ===== SHA256 with Crypto-js ===================================
|  Learn more: Crypto-js: https://github.com/brix/crypto-js      |
|  =============================================================*/

const SHA256 = require('crypto-js/sha256');

/* ===== Block Class ===================================
|  Class with a constructor for block data model       |
|  ====================================================*/

class Block {
  constructor(data){
    this.height = '';
    this.timeStamp = '';
    this.data = data;
    this.previousHash = '0x';
    this.hash = '';
  }
}

/* ===== Blockchain ===================================
|  Class with a constructor for blockchain data model  |
|  with functions to support:                          |
|     - createGenesisBlock()                           |
|     - getLatestBlock()                               |
|     - addBlock()                                     |
|     - getBlock()                                     |
|     - validateBlock()                                |
|     - validateChain()                                |
|  ====================================================*/

class Blockchain{
    constructor(){
      // new chain array
      this.chain = [];
      // add first genesis block
      this.addBlock(this.createGenesisBlock());
  }

  createGenesisBlock(){
    return new Block("First block in the chain - Genesis block");
  }

  // getLatest block method
  getLatestBlock(){
    return this.chain[this.chain.length -1];
  }

   // addBlock method
  addBlock(newBlock){
    // block height
    newBlock.height = this.chain.length;
    // UTC timestamp
    newBlock.timeStamp = new Date().getTime().toString().slice(0,-3);
    if (this.chain.length>0) {
      // previous block hash
      newBlock.previousHash = this.chain(this.chain.length-1.hash;
    }
    // SHA256 requires a string of data
    newBlock.hash = SHA256(JSON.stringify(newBlock)).toString();
    console.log(JSON.stringify(newBlock));
    // add block to chain
    this.chain.push(newBlock);
  }

LevelDB to Persist Data

Step 1: Comments

We modified the code to include comments for good practice ?

Step 2: Install level in the terminal

Then, we installed leveldb by running this command in the terminal:

npm install level --save

Step 3: Review levelSandbox.js

So far, you’ve created a simple blockchain. The problem with this model is that the data stored in it is not persisted (not very useful for a blockchain). To solve, we will need to find a simple storage method to help us store the data. We also shouldn’t use a centralized database because the purpose of the blockchain is to have decentralized data. A good solution would be to use LevelDB.

To prep you for integrating your private blockchain with LevelDB, I created the levelSandbox.js to demonstrate specific functionality you will build upon later.

InlevelSandbox.js we:

  • Added our level dependency
  • Established our storage location for the dataset
  • Configured our db object with levelDB
  • Setup addLevelDBData() which adds data to levelDB with a key/value pair
  • Setup getLevelDBData() which gets a value from a key
  • Setup addDataToLevelDB() which adds a new block
  • Setup theLoop() which tests leveldb using a self invoking function to add blocks to the chain

Currently levelSandbox.js is not tied to our simpleChain.js just yet, that’s what you’ll get to work on in the project.

Code

/* ===== Persist data with LevelDB ===================================
|  Learn more: level: https://github.com/Level/level     |
|  =============================================================*/

let level = require('level');
let chainDB = './chaindata';
let db = level(chainDB);

// Add data to levelDB with key/value pair
function addLevelDBData(key,value){
  db.put(key, value, function(err) {
    if (err) return console.log('Block ' + key + ' submission failed', err);
  })
}

// Get data from levelDB with key
function getLevelDBData(key){
  db.get(key, function(err, value) {
    if (err) return console.log('Not found!', err);
    console.log('Value = ' + value);
  })
}

// Add data to levelDB with value
function addDataToLevelDB(value) {
    let i = 0;
    db.createReadStream().on('data', function(data) {
          i++;
        }).on('error', function(err) {
            return console.log('Unable to read data stream!', err)
        }).on('close', function() {
          console.log('Block #' + i);
          addLevelDBData(i, value);
        });
}

/* ===== Testing ==============================================================|
|  - Self-invoking function to add blocks to chain                             |
|  - Learn more:                                                               |
|   https://scottiestech.info/2014/07/01/javascript-fun-looping-with-a-delay/  |
|                                                                              |
|  * 100 Milliseconds loop = 36,000 blocks per hour                            |
|     (13.89 hours for 500,000 blocks)                                         |
|    Bitcoin blockchain adds 8640 blocks per day                               |
|     ( new block every 10 minutes )                                           |
|  ===========================================================================*/


(function theLoop (i) {
  setTimeout(function () {
    addDataToLevelDB('Testing data');
    if (--i) theLoop(i);
  }, 100);
})(10);

Steps to follow

Step 1 Analyze LevelSandbox.js methods
Step 2 Let’s talk about the getBlocksCount() algorithm
Step 3 Run the application

Each step you’ll take to complete this exercise is called out in comments throughout the code. You can find more details and guidance about each of these steps in the text provided below the code.

Let’s get started!

Practice LevelDB and Promises

Step. 1. Analyze LevelSandbox.js methods

In the previous lesson, you saw us implement some methods from LevelDB using callbacks. In this practice, we will be using Promises. Promises allow us to work with the database in asynchronous way, but is very important to understand how to transform the methods to return Promises.

The fist method implemented is getLevelDBData(key). This method allow you to get the value corresponding to the key.

The second method implemented is addLevelDBData(key, value). This method allow you to insert data into the LevelDB.

The third method getBlocksCount() is the method that you need to implement, this is a very useful method because it will help you to get the how many objects you have inserted in your DB, for your future project this method can be use as way to calculate the height.

Step 2. Let’s talk about the getBlocksCount() algorithm

This is the method that we need to implement and it will be very useful for your next project. The simple way to describe this functionality is to find a method that allows us to count all the keys inserted in LevelDB right?

This method exists in LevelDB and it is createReadStream()

db.createReadStream()
.on('data', function (data) {
      // Count each object inserted
 })
.on('error', function (err) {
    // reject with error
 })
 .on('close', function () {
    //resolve with the count value
});

Read more about this in the documentation for LevelDB.

Step 3. Run the application

In the workspace below, open the app.js file. In there you have code that allows the application to insert objects in the database.

To run the application:

  • Open the terminal
  • Move to the project folder cd Project
  • Write in the console node app.js

Note: If you need to run your application several times, remember to delete the folder chaindata every time.

你可能感兴趣的:(BlockchainND)