关闭

初识区块链_用JS构建你自己的区块链

时间: 2018-12-04阅读: 793标签: 区块链

前言

区块链太复杂,那我们就讲点简单的。用js来构建你自己的区块链系统,寥寥几行代码就可以说明区块链的底层数据结构、POW挖矿思想和交易过程等。当然了,真实的场景远远远比这复杂。本文的目的仅限于让大家初步了解、初步认识区块链。
文章内容主要参考视频:Building a blockchain with JavaScript (https://www.youtube.com/playlist?list=PLzvRQMJ9HDiTqZmbtFisdXFxul5k0F-Q4)
感谢原作者,本文在原视频基础上做了修改补充,并加入了个人理解。


认识区块链

区块链顾名思义是由区块连接而成的链,因此最基本的数据结构是Block。每个Block都含有timestamp、data、hash、previousHash等信息。其中data用来存储数据,previousHash是前一个区块的hash值。示意如下:
技术分享图片
hash是对区块信息的摘要存储,hash的好处是任意长度的信息经过hash都可以映射成固定长度的字符串,如可用sha256:
calculateHash() {
    return SHA256(this.previousHash + this.timestamp + jsON.stringify(this.data)).toString();
}


Block的数据结构

Block的最基本数据结构如下:
class Block {
    constructor(timestamp, data, previousHash = ‘‘) {
        this.timestamp = timestamp;
        this.data = data;
        this.previousHash = previousHash;
        //对hash的计算必须放在最后,保证所有数据赋值正确后再计算
        this.hash = this.calculateHash(); 
    }

    calculateHash() {
        return SHA256(this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
    }
}


BlockChain的数据结构

多个Block链接而成BlockChain,显然可用用数组或链表来表示,如:
class BlockChain {
    constructor() {
        this.chain = [];
    }
}


创世区块

正所谓万物始于一,区块链的第一个区块总是需要人为来手动创建,这个区块的previousHash为空,如:
createGenesisBlock() {
    return new Block("2018-11-11 00:00:00", "Genesis block of simple chain", "");
}
区块链的构造方法也应改为:
class BlockChain {
    constructor() {
        this.chain = [this.createGenesisBlock()];
    }
}


添加区块

每新加一个区块,必须保证与原有区块链连接起来,即:
class BlockChain {
    getLatestBlock() {
        return this.chain[this.chain.length - 1];
    }
    
    addBlock(newBlock) {
        //新区块的前一个hash值是现有区块链的最后一个区块的hash值;
        newBlock.previousHash = this.getLatestBlock().hash;
        //重新计算新区块的hash值(因为指定了previousHash);
        newBlock.hash = newBlock.calculateHash(); 
        //把新区块加入到链中;
        this.chain.push(newBlock); 
    }
    ...
}


校验区块链

区块链数据结构的核心是保证前后链接、无法篡改,但是如果有人真的篡改了某个区块,我们该如何校验发现呢?最笨也是最自然是想法就是遍历所有情况,逐一校验,如:
isChainValid() {
    //遍历所有区块
    for (let i = 1; i < this.chain.length; i++) {
        const currentBlock = this.chain[i];
        const previousBlock = this.chain[i - 1];
        //重新计算当前区块的hash值,若发现hash值对不上,说明该区块有数据被篡改,hash值未重新计算
        if (currentBlock.hash !== currentBlock.calculateHash()) {
            console.error("hash not equal: " + JSON.stringify(currentBlock));
            return false;
        }
        //判断当前区块的previousHash是否真的等于前一个区块的hash,若不等,说明前一个区块被篡改,虽然hash值被重新计算正确,但是后续区块的hash值并未重新计算,导致整个链断裂
        if (currentBlock.previousHash !== previousBlock.calculateHash) {
            console.error("previous hash not right: " + JSON.stringify(currentBlock));
            return false;
        }
    }
    return true;
}


Just run it

跑起来看看,即:
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));


console.log(JSON.stringify(simpleChain, null, 4));

console.log("is the chain valid? " + simpleChain.isChainValid());
结果如下:
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js 
{
    "chain": [
        {
            "timestamp": "2018-11-11 00:00:00",
            "data": "Genesis block of simple chain",
            "previousHash": "",
            "hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
        },
        {
            "timestamp": "2018-11-11 00:00:01",
            "data": {
                "amount": 10
            },
            "previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
            "hash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"
        },
        {
            "timestamp": "2018-11-11 00:00:02",
            "data": {
                "amount": 20
            },
            "previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
            "hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
        }
    ]
}
is the chain valid? true

注意看其中的previousHash与hash,确实是当前区块的previousHash指向前一个区块的hash。


篡改下试试

都说区块链不可篡改,是真的吗?让我们篡改第2个区块试试,如:
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));

console.log("is the chain valid? " + simpleChain.isChainValid());

//将第2个区块的数据,由10改为15
simpleChain.chain[1].data = {amount: 15};

console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4));
结果如下:
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js 
is the chain valid? true
hash not equal: {"timestamp":"2018-11-11 00:00:01","data":{"amount":15},"previousHash":"fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89","hash":"150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"}
is the chain still valid? false
{
    "chain": [
        {
            "timestamp": "2018-11-11 00:00:00",
            "data": "Genesis block of simple chain",
            "previousHash": "",
            "hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
        },
        {
            "timestamp": "2018-11-11 00:00:01",
            "data": {
                "amount": 15
            },
            "previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
            "hash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"
        },
        {
            "timestamp": "2018-11-11 00:00:02",
            "data": {
                "amount": 20
            },
            "previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
            "hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
        }
    ]
}

显然,篡改了数据之后,hash值并未重新计算,导致该区块的hash值对不上。


再篡改下试试

那么,如果我们聪明点,篡改后把hash值也重新计算会如何?
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));

console.log("is the chain valid? " + simpleChain.isChainValid());
//篡改后重新计算hash值
simpleChain.chain[1].data = {amount: 15};
simpleChain.chain[1].hash = simpleChain.chain[1].calculateHash();
console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4));
结果如下:
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js 
is the chain valid? true
previous hash not right: {"timestamp":"2018-11-11 00:00:02","data":{"amount":20},"previousHash":"150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529","hash":"274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"}
is the chain still valid? false
{
    "chain": [
        {
            "timestamp": "2018-11-11 00:00:00",
            "data": "Genesis block of simple chain",
            "previousHash": "",
            "hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
        },
        {
            "timestamp": "2018-11-11 00:00:01",
            "data": {
                "amount": 15
            },
            "previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
            "hash": "74d139274fb692495b7c805dd5822faa0c5b5e6058b6beef96e87e18ab83a6b1"
        },
        {
            "timestamp": "2018-11-11 00:00:02",
            "data": {
                "amount": 20
            },
            "previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
            "hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
        }
    ]
}

显然,第3个区块的previousHash并未指向第2个区块的hash。


是真的无法篡改吗

其实并不是,如果我们再聪明一点,把后续区块的hash值也重新计算一下,不就OK了吗? 确实如此,如:
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));

console.log("is the chain valid? " + simpleChain.isChainValid());
//篡改第2个区块
simpleChain.chain[1].data = {amount: 15};
simpleChain.chain[1].hash = simpleChain.chain[1].calculateHash();
//并把第3个区块也重新计算
simpleChain.chain[2].previousHash = simpleChain.chain[1].hash;
simpleChain.chain[2].hash = simpleChain.chain[2].calculateHash();
console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4

 

原文链接

站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/1491

关闭

区块链与数据库到底有何不同?只是名字不一样吗?

区块链被诟病的一大原因,就是区块链分布式账本技术(DLT)已经被吹捧成了一剂包治百病的良药,从支付处理和供应链跟踪到数字身份,再到版权保护

传统业务如何运用区块链技术

随着十几年的区块链技术的发展,比特币不再是作为区块链应用的代表。随着区块链的去中心化、不可纂改等特性被人熟悉后,传统企业要生存,那么就要创新,故越来越多的传统企业开始转型

Web 3.0 前瞻:基于区块链的下一代浏览器

​现在有很多人把区块链崛起成为明星技术的历程,与互联网商业发展的黎明时代相提并论。在 90 年代初期,许多人对待新鲜技术持谨慎态度,却很少有人真正预见到人类的创新活动将会在未来 20 年中拓展到多远的边界

区块链到底是个什么链?

这段时间,估计你已经看了不少关于区块链应用前景的解读,可能还琢磨了一些区块链概念股的行情走势。但如果没猜错的话,你可能还是不太清楚, 区块链它到底是个什么链。

NodeJS实现简易区块链

很多区块链接在一起,就组成了一条链。这条链,也用class来表示。并且其中实现了很多方法:按照加密规则生成hash,插入新块和检查操作,批量插入块和检查操作以及可信度计算

用JavaScript写一个区块链

几乎每个人都听说过像比特币和以太币这样的加密货币,但是只有极少数人懂得隐藏在它们背后的技术。在这篇博客中,我将会用JavaScript来创建一个简单的区块链来演示它们的内部究竟是如何工作的

刚入门区块链的程序员应该看些什么?

区块链有很多的定义,大家的说法都不一样,业界都还没有统一。每个人心中都有自己的哈姆雷特。所以此处就不做定义了。那么我主要推荐一些关于区块链概念的学习资料,看完我所推荐的资料,你应该对这门技术有一个自己的了解

从POW到POS看区块链共识的发展

共识机制是区块链的灵魂。就像一个国家的法律,维系着区块链世界的正常运作。区块链最早的共识是工作量证明(POW),比特币和以太坊都是采用的工作量证明。现在流行的一个趋势是权益证明(POS)。以太坊2.0就会采用 POS 共识

区块链技术的三个常见误区

区块链于2009年首次推出,并发布了其首个应用程序——比特币。如果按照最简单的应用方式来解释, 区块链是一种去中心化的数字记录系统,令不受信任的交易各方可以共享数字历史记录,并且无需中介即可达成共识

区块链项目如何投资?

区块链一词最近在各种风险投资活动中被频繁使用。许多投资者都预感到风要来了,想提前做一些赛道布置,但他们不想盲目地支付学费。当与许多机构投资者谈论区块链时,基本的答案是看看它。普遍的感觉是项目太少,估价太高

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!