區塊鏈入門學習(1)

什麼是區塊鏈

生活中區塊鏈小栗子

現在家裏有三口人,爸爸,媽媽和兒子。他們開始約定由爸爸記賬,媽媽買菜了花了20元,爸爸加了一升油花了50元,這些都會被爸爸記在本子上(集中式)。有一天,爸爸突然想私自買包煙抽,於是在本子上做了手腳,媽媽沒有發現,卻被兒子發現了,媽媽卻無可奈何,因爲賬本在爸爸手上,沒有紕漏。於是,媽媽提議,三口人每個人都要做賬本,當發現異常時,校對一下就知道哪個是錯誤的了,於是,家裏就有了三份賬本(分佈式),每個人的資金有變動,都要廣播一下,讓另外的人記賬。那麼問題來了,這樣每次都要每個人記賬,是不是很費力啊,要是我,肯定覺得麻煩。但是,如果媽媽說,每記一筆都會有金幣獎勵,且只給第一個記完的人。那大家都會踊躍記賬,又有問題出現了,兒子爲了得到獎勵去買喜愛的零食,就寫得很潦草,完全看不懂(醫生們的筆記,哈哈),媽媽發現了,提出,我們需要達成共識,我們要用格子紙寫,每格一個字,每行空兩格,要用正楷。同時,爲了保證數據同步,我們要把前一個人的消費和時間,簽名進行覈對,沒有錯誤以後,我們才能寫進去,一直按規範做到最新的狀態。
這樣,要想做假賬的話,除非賄賂一個人和你一起篡改一模一樣的賬本,否則是就是做不到的。

栗子🌰小結

那以上的賬本,我們就可以說是一條區塊鏈。每一筆交易就是一個區塊。記賬的人,我們稱之爲曠工,爲了獲取獎勵,我們採用格子紙和正楷規範地記賬過程就是挖礦。最後,我們引用共識機制保證數據同步和正確地持續鏈接下去。

簡單來說,區塊鏈就是由一個一個的包含着信息的區塊連接起來的信息鏈。其中,包含的信息主要包括主體信息data、時間戳timestamp、前hash,本身hash,隨機值nonce和本身的序號index等。用js代碼表示即爲:

const firstBlock = {
    timestamp: 1550155109024,//時間戳
    prevHash: '0',//前一個hash
    nonce:0,  //隨機值
    hash: 'b788ba63a91f9fcbae92154679da5df7551939518e81aca280745c9eadb51fbd',//本身hash
    index: 0,  //序號
    data: {
		info:'I am a firstBlock in BlockChain'
	},//信息主體
}

那麼,我們可以對區塊做一個簡單的分解,分爲區塊頭和區塊體。區塊頭(時間戳timestamp、前hash,本身hash)和區塊體(主體信息data)
區塊分解
每一個區塊會根據自身區塊裏的其他值生成本身hash,後面的區塊依據preHash來鏈接。一個一個地向前追溯,那麼第一個就沒有preHash,也就是我們常說的創世區塊。
在這裏插入圖片描述
這裏就會有了區塊鏈的幾個重要的特點,其本身不可被篡改、存儲數據。那麼,我們現在可以說,區塊鏈是由一個個任何人都可以訪問的區塊構成的分佈式的,且不可變的數據庫。一旦一個區塊被添加或者被篡改,除非讓剩餘的其餘區塊失效,否則它是不會再被改變的。但這是不可能的。對於要製作虛假交易,除非你說服了全網裏超過51%的礦工都更改某一筆賬目,否則你的篡改都是無效的。網絡中參與人數越多,實現造假可能性越低。

hash

爲了驗證鏈的正確性,我們需要比對鏈中每個區塊的信息,最後一一比對完,這樣的工作量是非常大的。因此我們在區塊鏈中,用到的hash算法是SHA256。爲什麼用hash算法呢?
因爲hash有以下特點:

  • 可以根據相同信息生成一組相同的串
  • 根據串無法倒推出生成該串的信息
  • 信息方發生細微變化,得到的值將會變得面目全非。

這裏用到的Hash算法不僅起到了驗證鏈的正確性以外,還提供了合理的工作量證明(pow)。這裏的pow方式我們發放到第二章,用代碼給大家講解。

說到代碼,額。該到正題了,我們就用js來實現下簡單的區塊鏈的成鏈及相關驗證

js實現簡單的區塊鏈的成鏈及相關驗證

首先我們要創建一個區塊類,來表示區塊:

class EasyBlock {
    constructor(index, timestamp, data, prevHash = '') {
        this.index = index;
        this.prevHash = prevHash;
        this.timestamp = timestamp;
        this.data = data;
        this.hash = this.calHash();
    }

    calHash() {
        return crypto
            .createHash('sha256')
            .update(this.index + this.timestamp + this.data + this.prevHash)
            .digest('hex')
    }
}

其中我們有五個基本的屬性和一個方法calHash(),來計算當前區塊的hash值。引入了node裏的crypto庫。

走起!!再來定義一個鏈的類,進行鏈的表示:

class EasyChain {
    constructor() {
        this.blockchain = [
            this.getInitBlock()
        ];
    }

    getInitBlock() {
        return new EasyBlock(0, 1550155109024, 'Hi,I am initBlock in EasyChain!', 0)
    }
}

首先我們是設計了一個創世區塊,給了初始值。俗話說的好,獨木不成林,獨塊不成鏈😁。那麼我們接下來就需要在這個鏈里加方法addBlock()來增加區塊。同時,我們需要知道上一區塊的相關信息,以鏈起來。我們就需要getLastBlock()這個方法了。

addBlock(newblock) {
   newblock.prevHash = this.getLastBlock().hash;
   newblock.hash = newblock.calHash();
}
getLastBlock() {
   return this.blockchain[this.blockchain.length - 1]
}

簡單的成鏈我們算是做完了!Give Me Five!
對了,還有一點我們不能忘了。還要校驗區塊和整個區塊鏈的正確性。那我們再加一個驗證方法,我們從最後一個區塊開始逐個驗證。

isValid(chain = this.blockchain) {
        for (let i = 1; i < chain.length; i++) {//從最後一個區塊開始逐個驗證
            const currentBlock = chain[i];
            const previousBlock = chain[i - 1];

            if (currentBlock.hash !== currentBlock.calHash()) { //驗證當前區塊的合法性
                return false;
            }
            if (currentBlock.prevHash !== previousBlock.hash) {//驗證是否可以成鏈
                return false;
            }
        }
        if (JSON.stringify(this.getInitBlock()) !== JSON.stringify(chain[0])) {//驗證創世區塊
            return false
        }
        return true
    }

最後我們再加一個展示區塊鏈的方法。

 showChain() {
        console.log('當前區塊鏈爲:' + JSON.stringify(this.blockchain))
 }

這樣我們就可以試試,我們自己的簡單區塊鏈easy-chain了。

let easyChain = new EasyChain();
easyChain.addBlock(new EasyBlock(1, new Date('2019/01/01').getTime(), '我是第二塊'))
easyChain.addBlock(new EasyBlock(2, new Date('2019/01/02').getTime(), '我是第三塊'))
easyChain.addBlock(new EasyBlock(3, new Date('2019/01/03').getTime(), '我是第四塊'))
easyChain.showChain()

我們可看到成鏈了:

當前區塊鏈爲:[
{"index":0,"prevHash":0,"timestamp":1550155109024,"data":"Hi,I am initBlock in EasyChain!","hash":"ef38230827465f53e65f1f9af2f55abd7519939fdd5b5423e9d7e0c7eb58513a"},
{"index":1,"prevHash":"ef38230827465f53e65f1f9af2f55abd7519939fdd5b5423e9d7e0c7eb58513a","timestamp":1546272000000,"data":"我是第二塊","hash":"6e2e15b10664e92f840839302843fc1fda80f24be1caf9ac09935ce307c0d37d"},
{"index":2,"prevHash":"6e2e15b10664e92f840839302843fc1fda80f24be1caf9ac09935ce307c0d37d","timestamp":1546358400000,"data":"我是第三塊","hash":"0e5ac9045df3a433c2708db9ccc53a2277e47cf40df6a64a21860dd87dfb7309"},
{"index":3,"prevHash":"0e5ac9045df3a433c2708db9ccc53a2277e47cf40df6a64a21860dd87dfb7309","timestamp":1546444800000,"data":"我是第四塊","hash":"6533a0d95a6d510b4e5cc0ca0e8523a46ce0417c91a6934351028d574bcca7b5"}
]

現在我們改變一下當前的區塊值,

console.log('改變前校驗結果爲:' + easyChain.isValid())
easyChain.blockchain[1].index = 4
console.log('改變後校驗結果爲:' + easyChain.isValid())

輸出給的是:

當前區塊鏈爲:[
{"index":0,"prevHash":0,"timestamp":1550155109024,"data":"Hi,I am initBlock in EasyChain!","hash":"ef38230827465f53e65f1f9af2f55abd7519939fdd5b5423e9d7e0c7eb58513a"},{"index":1,"prevHash":"ef38230827465f53e65f1f9af2f55abd7519939fdd5b5423e9d7e0c7eb58513a","timestamp":1546272000000,"data":"我是第二塊","hash":"6e2e15b10664e92f840839302843fc1fda80f24be1caf9ac09935ce307c0d37d"},{"index":2,"prevHash":"6e2e15b10664e92f840839302843fc1fda80f24be1caf9ac09935ce307c0d37d","timestamp":1546358400000,"data":"我是第三塊","hash":"0e5ac9045df3a433c2708db9ccc53a2277e47cf40df6a64a21860dd87dfb7309"},{"index":3,"prevHash":"0e5ac9045df3a433c2708db9ccc53a2277e47cf40df6a64a21860dd87dfb7309","timestamp":1546444800000,"data":"我是第四塊","hash":"6533a0d95a6d510b4e5cc0ca0e8523a46ce0417c91a6934351028d574bcca7b5"}
]
改變前校驗結果爲:true
改變後校驗結果爲:false

校驗成功啦!!這一篇暫時先分享自己學的這麼多了,接下來會給大家分享下挖礦原理!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章