主页 > 下载官方imtoken钱包 > 30分钟自己写一个区块链(一)

30分钟自己写一个区块链(一)

下载官方imtoken钱包 2023-12-30 05:07:35

阅读时间:10 分钟聊天

去年在币圈动荡、币价飞涨的时候,我们看到了很多优秀的区块链产品在背后出现,也看到了很多以集资为目的的“空气币”。 很多人对区块链的兴趣也越来越浓,那么加密货币背后的区块链到底有多少技术含量呢? 我们甚至可以从头开始实施区块链吗? 答案当然是可以的,我们可以创建一条链。 今天,就简单的说一下吧。

比特币交易链区块拥堵_比特币多久产生一个区块_比特币几分钟产生一个区块

(图为初生Ethercat,价值250ETH,截至发稿时价值约28万美元)

什么是加密货币?

在大多数实现中,加密货币只是其区块链中相应账户的余额。 对于每一笔交易,当绝大多数区块链节点证明交易合法时,余额从一个账户转移到另一个账户并在整个网络中更新。 同时,为算力付费的节点可以获得交易手续费,就像银行转账手续费一样。

什么是区块链?

一般来说,区块链(BlockChain)是由一个个称为区块的账本组成。 所有分类帐在维护区块链网络的每个节点上都有完整的副本。 区块的内容经过哈希处理(Hash),并在分布式系统中链接在一起。 每个块可以包含许多事务、文件或任意数据。 新区块被发现后,会将这些数据作为一个整体进行哈希处理,成为一个很短的哈希码,存储在新区块中。 如果不清楚什么是hash,可以看原版的另一篇文章:什么是hash? 5分钟让你看懂

比特币交易链区块拥堵_比特币多久产生一个区块_比特币几分钟产生一个区块

比特币几分钟产生一个区块_比特币交易链区块拥堵_比特币多久产生一个区块

(比特币的区块链图,每个区块存储前一个区块所有内容的hash)

区块链的不变性就是通过这样的链哈希来实现的。 试想一下,如果我要改变一个区块中的内容,它必然会改变它的哈希值,这意味着后续所有区块中的哈希值都必然会改变,维护网络的节点当然不会同意,除非我的算力可以大于全网算力的50%(在某些情况下,攻击所需的算力更低)。

如何从技术上实现区块链?

首先,假定读者具有基本的编程技能。 虽然本文是用 Javascript 编写的,但是掌握任何一种编程语言的读者阅读起来应该没有任何困难。

只想看最终代码? 点击下方Github链接原文。

开发准备

比特币多久产生一个区块_比特币交易链区块拥堵_比特币几分钟产生一个区块

我们首先需要安装最新版本的Node.js,可以通过NVM安装。

  1. curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash

  2. nvm install 9.4.0

  3. node -v

第一步是建立区块链模型

让我们首先构建一个可以创建新块和创建交易的区块链模型。

  1. 'use strict';

  2. //定义一个class,叫Blockchain,每一个区块链都是这个class的实例

  3. class Blockchain {

  4.    constructor() {

  5.        this.chain = []; // 储存所有区块

  6.        this.difficulty = 1; // 挖矿的难度

  7.    }

  8.    createBlock() {

  9.        // 创造一个新区块

  10.    }

  11.    createTransaction() {

  12.        // 创建一个交易

  13.    }

  14.    static hash(block) {

  15.        // 对一个区块进行哈希

  16.    }

  17.    static latesBlock() {

  18.        // 取得链上的最后一个区块

  19.    }

  20. }

这里我想解释一下区块(block)和交易(transaction)是什么样子的。 虽然不同区块链的区块模型差异很大,但一些最基本的元素是相同的。 基本块如下所示:

  1. var block = {

  2.    timestamp: 1516245715528,

  3.    id: 0,

  4.    proof: 786453290000,

  5.    previousBlockHash: "12f79cda4fb3f084531de2034e6b4acf"

  6.    transactions: [{

  7.        sender: "0xca35b7d915458ef540ade6068dfe2f44e8fa733c",

  8.        receiver: "0x14723a09acff6d2a60dcdf7aa4aff308fddc160c",

  9.        value: 100

  10.    }]

  11. }

可以看出,一个区块包含了它被挖出时的时间戳(timestamp)、它在区块链中的位置(id)、它的证明(proof,后面会讲到更多)、前一个区块的整体哈希值( previousBlockHash),包括交易(transactions)。 作为最基本的交易模型,每笔交易只包括发送方的地址(sender)、接收方的地址(receiver)和本次交易的价值(value)。

比特币多久产生一个区块_比特币交易链区块拥堵_比特币几分钟产生一个区块

第二步实现基本功能工具功能

这里我们首先实现一个效用函数Hash(block),它会帮助我们散列一个块。 这个函数会在我们挖矿(发现新区块)的时候用到。

  1.    static hash(block) {

  2.        // 对一个区块进行哈希:

  3.        // 现将block转换成base64

  4.        // 将得到的结果进行SHA哈希

  5.        var blockStr = JSON.stringify(block);

  6.        var blockB64 = new Buffer(blockStr).toString('base64');

  7.        var newHash = crypto.createHash('sha256');

  8.        newHash.update(blockB64);

  9.        return newHash.digest('hex');

  10.    }

此函数将一个块(一个 Javascript 对象)散列为一个字符串。 我们使用的是 crypto 工具,它已经内置在最新版本的 Node.js 中,所以我们不需要安装它。

创建新交易

接下来,我们实现创建新事务的方法。

  1.    createTransaction(sender, receiver, value) {

  2.        // 创建一个交易

  3.        // 根据提供的sender, receiver地址,以及转账的价值,建立一个交易

  4.        // 并把它加入到我们的区块链里

  5.        var transaction = {

  6.            sender: sender,

  7.            receiver: receiver,

  8.            value: value

  9.        };

  10.        this.lastBlock.transactions.push(transaction);

  11.        return this.lastBlock.id;

  12.    }

非常直观,我们只是创建了一个对象,将它添加到区块链并返回了它。

比特币多久产生一个区块_比特币交易链区块拥堵_比特币几分钟产生一个区块

创建一个新块

现在让我们实现创建块的代码。 当我们的区块链甚至没有区块时,我们需要创建第一个区块(创世区块)比特币几分钟产生一个区块,我们在构造函数中实现它。

  1.    constructor() {

  2.        this.chain = []; // 储存所有区块

  3.        this.difficulty = 1; // 挖矿的难度

  4.        this.chain.push(this.createBlock(1)); // 创建第一个区块

  5.    }

  6.    createBlock(previousHash = undefined) {

  7.        // 创造一个新区块

  8.        // 一开始的proof是0,不一定是有效的,所以我们需要mineProof来找到有效的proof

  9.        var block = {

  10.            timestamp: Date.now(),

  11.            id: this.chain.length,

  12.            proof: 0,

  13.            previousBlockHash: previousHash || this.constructor.hash(this.lastBlock()),

  14.            transactions: []

  15.        };

  16.        self.mineProof(block);

  17.        this.chain.push(block);

  18.    }

在创建新区块时,我们使用当前时间的时间戳,使用当前区块链的长度作为id,将初始证明设置为0(证明将在下一步中详细讨论),并转换之前的区块整体Hash并赋值给previousBlockHash。 在创建创世块时,我们将 previousBlockHash 设置为 1。为了便于理解,我们在创建新块时不附加任何交易。 实际情况是,矿工可以选择包含哪些交易,需要对这些交易进行处理比特币几分钟产生一个区块,得到一棵默克尔树。

了解挖矿:寻找有效证据

读者朋友应该听说过工作量证明。 POW 是区块链中用于创建区块的核心算法或机制。 POW本身的目的就是为了找到一个数来解决一个数学问题,而且找到这个数的难度越来越高,但是一旦找到了,就很容易证明它解决了这个数学问题。 可以很快做到。 当然,除了工作量证明,我们还有空间证明和权益证明。 在代码中,我们使用 proof 来表示我们找到的数字。 那么这道数学题到底是什么? 让我们用一个例子来回答。

给定一个数A,我们要找到一个数B,使得Hash(A*B)的结果C的最后一位等于0。即C可以是Hash(A*B)=2ba83... 6d0,因为它的最后一位是0。如果我们用Javascript找到这个B,我们可以这样做:

  1. const crypto = require('crypto');

  2. var A = 10; // 我们给定A一个值

  3. var B = 0; // B从0开始

  4. while (true) {

  5.    var multiplied = A * B;

  6.    var hash = crypto.createHash('sha256').update(multiplied.toString()).digest('hex');

  7.    if (hash.substr(hash.length - 1) == "0") {

  8.        console.log(hash);

  9.        break;

  10.    } else {

  11.        B += 1;

  12.    }

  13. }

  14. console.log(B);

比特币交易链区块拥堵_比特币多久产生一个区块_比特币几分钟产生一个区块

让我们尝试在终端中运行这段代码,我们可以看到我们找到了一个满足这个条件的数字 24。

  1. node test.js

  2. 6af1f692e9496c6d0b668316eccb93276ae6b6774fa728aac31ff40a38318760

  3. 24

可以想象,如果我们要求最终哈希值的最后2位为0,甚至3位、4位,那么找到B的难度应该更高,这就是POW调整挖矿难度的方式。

实现挖矿

知道如何挖矿后,我们将上面的代码集成到我们的区块链模型中。

  1.    isProofValid(tentativeBlock) {

  2.        // 这里我们判断newProof是不是一个合法的proof的方法是

  3.        // 将整个区块进行哈希

  4.        // 如果得到的散列值指的最后n位都是0,那么这是一个valid proof

  5.        // 其中,n = difficulty

  6.        var result = this.constructor.hash(tentativeBlock);

  7.        return result.substr(result.length - this.difficulty) == '0'.repeat(this.difficulty);

  8.    }

  9.    mineProof(tentativeBlock) {

  10.        while (!this.isProofValid(tentativeBlock)) {

  11.            tentativeBlock.proof += 1; // 如果不是可用的proof,我们就接着枚举

  12.        }

  13.    }

  14.    createBlock(previousHash = undefined) {

  15.        // 创造一个新区块

  16.        // 一开始的proof是0,不一定是有效的,所以我们需要mineProof来找到有效的proof

  17.        var block = {

  18.            timestamp: Date.now(),

  19.            id: this.chain.length,

  20.            proof: 0,

  21.            previousBlockHash: previousHash || this.constructor.hash(this.lastBlock()),

  22.            transactions: []

  23.        };

  24.        self.mineProof(block);

  25.        this.chain.push(block);

  26.    }

因为我们从一开始就定义了如何散列一个块,所以我们可以在这里重用它。 至此,我们基本实现了区块链中创建区块和创建交易的功能。 整体代码贴在下面。 下一次,我们会将我们编写的区块链API化并部署到多个节点,敬请期待。

  1. 'use strict';

  2. const crypto = require('crypto');

  3. //定义一个class,叫Blockchain,每一个区块链都是这个class的实例

  4. class Blockchain {

  5.    constructor() {

  6.        this.chain = []; // 储存所有区块

  7.        this.difficulty = 1; // 挖矿的难度

  8.        this.chain.push(this.createBlock(1)); // 创建第一个区块

  9.    }

  10.    isProofValid(tentativeBlock) {

  11.        // 这里我们判断newProof是不是一个合法的proof的方法是

  12.        // 将整个区块进行哈希

  13.        // 如果得到的散列值指的最后n位都是0,那么这是一个valid proof

  14.        // 其中,n = difficulty

  15.        var result = this.constructor.hash(tentativeBlock);

  16.        return result.substr(result.length - this.difficulty) == '0'.repeat(this.difficulty);

  17.    }

  18.    mineProof(tentativeBlock) {

  19.        while (!this.isProofValid(tentativeBlock)) {

  20.            tentativeBlock.proof += 1; // 如果不是可用的proof,我们就接着枚举

  21.        }

  22.    }

  23.    createBlock(previousHash = undefined) {

  24.        // 创造一个新区块

  25.        // 一开始的proof是0,不一定是有效的,所以我们需要mineProof来找到有效的proof

  26.        var block = {

  27.            timestamp: Date.now(),

  28.            id: this.chain.length,

  29.            proof: 0,

  30.            previousBlockHash: previousHash || this.constructor.hash(this.lastBlock()),

  31.            transactions: []

  32.        };

  33.        self.mineProof(block);

  34.        this.chain.push(block);

  35.    }

  36.    createTransaction(sender, receiver, value) {

  37.        // 创建一个交易

  38.        // 根据提供的sender, receiver地址,以及转账的价值,建立一个交易

  39.        // 并把它加入到我们的区块链里

  40.        var transaction = {

  41.            sender: sender,

  42.            receiver: receiver,

  43.            value: value

  44.        };

  45.        this.lastBlock.transactions.push(transaction);

  46.        return this.lastBlock.id;

  47.    }

  48.    static hash(block) {

  49.        // 对一个区块进行哈希:

  50.        // 现将block 转换成base64

  51.        // 将得到的结果进行SHA哈希

  52.        var blockStr = JSON.stringify(block);

  53.        var blockB64 = new Buffer(blockStr).toString('base64');

  54.        var newHash = crypto.createHash('sha256');

  55.        newHash.update(blockB64);

  56.        return newHash.digest('hex');

  57.    }

  58.    lastBlock() {

  59.        // 取得链上的最后一个区块

  60.        return this.chain[this.chain.length - 1];

  61.    }

  62. }