200 行代码实现一个简单的区块链

2023-11-12


java|区块链开发与交流群: 613121183

有兴趣的也可以加下哈,提供了不少区块链资料,以后有资料可以相会共享

区块链的基础概念很简单:一个分布式数据库,存储一个不断加长的 list,list 中包含着许多有序的记录。然而,在通常情况下,当我们谈到区块链的时候也会谈起使用区块链来解决的问题,这两者很容易混淆。像流行的比特币和以太坊这样基于区块链的项目就是这样。“区块链”这个术语通常和像交易、智能合约、加密货币这样的概念紧紧联系在一起。

这就令理解区块链变得不必要得复杂起来,特别是当你想理解源码的时候。下面我将通过 200 行 JS 实现的超级简单的区块链来帮助大家理解它,我给这段代码起名为 NaiveChain。

块结构

第一个逻辑步骤是决定块结构。为了保证事情尽可能的简单,我们只选择最必要的部分:index(下标)、timestamp(时间戳)、data(数据)、hash(哈希值)和 previous hash(前置哈希值)。

这个块中必须能找到前一个块的哈希值,以此来保证整条链的完整性。

1
2
3
4
5
6
7
8
9
class Block {
     constructor ( index , previousHash , timestamp , data , hash ) {
         this . index = index ;
         this . previousHash = previousHash . toString ( ) ;
         this . timestamp = timestamp ;
         this . data = data ;
         this . hash = hash . toString ( ) ;
     }
}

块哈希

为了保存完整的数据,必须哈希区块。SHA-256会对块的内容进行加密,记录这个值应该和“挖矿”毫无关系,因为这里不需要解决工作量证明的问题。

1
2
3
var calculateHash = ( index , previousHash , timestamp , data ) = > {
     return CryptoJS . SHA256 ( index + previousHash + timestamp + data ) . toString ( ) ;
} ;

块的生成

要生成一个块,必须知道前一个块的哈希值,然后创造其余所需的内容(= index, hash, data and timestamp)。块的data部分是由终端用户所提供的。

1
2
3
4
5
6
7
var generateNextBlock = ( blockData ) = > {
     var previousBlock = getLatestBlock ( ) ;
     var nextIndex = previousBlock . index + 1 ;
     var nextTimestamp = new Date ( ) . getTime ( ) / 1000 ;
     var nextHash = calculateHash ( nextIndex , previousBlock . hash , nextTimestamp , blockData ) ;
     return new Block ( nextIndex , previousBlock . hash , nextTimestamp , blockData , nextHash ) ;
} ;

块的存储

内存中的Javascript数组被用于存储区块链。区块链的第一个块通常被称为“起源块”,是硬编码的。

1
2
3
4
5
var getGenesisBlock = ( ) = > {
     return new Block ( 0 , "0" , 1465154705 , "my genesis block!!" , "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7" ) ;
} ;
 
var blockchain = [ getGenesisBlock ( ) ] ;

确认块的完整性

在任何时候都必须能确认一个区块或者一整条链的区块是否完整。在我们从其他节点接收到新的区块,并需要决定接受或拒绝它们时,这一点尤为重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
var isValidNewBlock = ( newBlock , previousBlock ) = > {
     if ( previousBlock . index + 1 !== newBlock . index ) {
         console . log ( 'invalid index' ) ;
         return false ;
     } else if ( previousBlock . hash !== newBlock . previousHash ) {
         console . log ( 'invalid previoushash' ) ;
         return false ;
     } else if ( calculateHashForBlock ( newBlock ) !== newBlock . hash ) {
         console . log ( 'invalid hash: ' + calculateHashForBlock ( newBlock ) + ' ' + newBlock . hash ) ;
         return false ;
     }
     return true ;
} ;

选择最长的链

任何时候在链中都应该只有一组明确的块。万一冲突了(例如:两个结点都生成了72号块时),会选择有最大数目的块的链。

1
2
3
4
5
6
7
8
9
var replaceChain = ( newBlocks ) = > {
     if ( isValidChain ( newBlocks ) && newBlocks . length > blockchain . length ) {
         console . log ( 'Received blockchain is valid. Replacing current blockchain with received blockchain' ) ;
         blockchain = newBlocks ;
         broadcast ( responseLatestMsg ( ) ) ;
     } else {
         console . log ( 'Received blockchain invalid' ) ;
     }
} ;

与其他结点的通信

结点的本质是和其他结点共享和同步区块链,下面的规则能保证网络同步。

  • 当一个结点生成一个新块时,它会在网络上散布这个块。
  • 当一个节点连接新peer时,它会查询最新的block。
  • 当一个结点遇到一个块,其index大于当前所有块的index时,它会添加这个块到它当前的链中,或者到整个区块链中查询这个块。

如图为当节点遵循前文所述协议时会发生的一些典型通信场景

我没有采用自动发现peer的工具。peers的位置(URL)必须是手动添加的。

结点控制

在某种程度上用户必须能够控制结点。这一点通过搭建一个HTTP服务器可以实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var initHttpServer = ( ) = > {
     var app = express ( ) ;
     app . use ( bodyParser . json ( ) ) ;
 
     app . get ( '/blocks' , ( req , res ) = > res . send ( JSON . stringify ( blockchain ) ) ) ;
     app . post ( '/mineBlock' , ( req , res ) = > {
         var newBlock = generateNextBlock ( req . body . data ) ;
         addBlock ( newBlock ) ;
         broadcast ( responseLatestMsg ( ) ) ;
         console . log ( 'block added: ' + JSON . stringify ( newBlock ) ) ;
         res . send ( ) ;
     } ) ;
     app . get ( '/peers' , ( req , res ) = > {
         res . send ( sockets . map ( s = > s . _socket . remoteAddress + ':' + s . _socket . remotePort ) ) ;
     } ) ;
     app . post ( '/addPeer' , ( req , res ) = > {
         connectToPeers ( [ req . body . peer ] ) ;
         res . send ( ) ;
     } ) ;
     app . listen ( http_port , ( ) = > console . log ( 'Listening http on port: ' + http_port ) ) ;
} ;

用户可以用下面的方法和结点互动:

  • 列出所有的块
  • 用用户提供的内容创建一个新的块
  • 列出或者新增peers

下面这个Curl的例子就是最直接的控制结点的方法:

1
2
#get all blocks from the node
curl http : //localhost:3001/blocks

体系结构

需要指出的是,节点实际上展现了两个web服务器:一个(HTTP服务器)是让用户控制节点,另一个(Websocket HTTP服务器)。

NaiveChain的主要组成部分

总结

创造 NaiveChain 的目的是为了示范和学习,因为它并没有“挖矿”算法(PoS of PoW),不能被用于公用网络,但是它实现了区块链运作的基本特性。

你可以在 Github 库中查看更多的技术细节。 https://github.com/lhartikk/naivechain



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

200 行代码实现一个简单的区块链 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 我可以使用 HSQLDB 进行 junit 测试克隆 mySQL 数据库吗

    我正在开发一个 spring webflow 项目 我想我可以使用 HSQLDB 而不是 mysql 进行 junit 测试吗 如何将我的 mysql 数据库克隆到 HSQLDB 如果您使用 spring 3 1 或更高版本 您可以使用 s
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • 如何将 pfx 文件转换为 jks,然后通过使用 wsdl 生成的类来使用它来签署传出的肥皂请求

    我正在寻找一个代码示例 该示例演示如何使用 PFX 证书通过 SSL 访问安全 Web 服务 我有证书及其密码 我首先使用下面提到的命令创建一个 KeyStore 实例 keytool importkeystore destkeystore
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • 【软件工程】之结构化设计

    结构化设计思考题如下 一 软件结构图 1 主要元素 2 形态特征指标 3 优化准则 1 模块独立性准则 2 软件结构的形态特征准则 3 模块的大小准则 4 模块控制域与作用域的准则 5 模块的接口准则 二 数据流模型 1 类型 1 变换流
  • QT中的信号与槽连接关系

    对于QT的信号与槽 进行一个信号连接两个槽 QT中connect的连接类型 AutoConnection在单线程中 按照默认的循序去触发相应的槽函数 DirectConnection在单线程中 对应的slot函数会被立刻调用 优先级高于主线
  • Angular开发(十四)-利用angular的http转发、即代理http 请求,处理项目中请求跨域的问题

    虽然angular的http请求中提供了jsonp处理跨域问题 但是不常用 我们web服务器端可能会选择别的方式处理 web服务器端使用nginx进行反向代理处理 使用nodejs中node http proxy解决本地开发ajax跨域问题
  • Com Surrogate

    昨晚 偶然间发现自己只要打开AVI格式的视频 电脑右下角的任务栏就会跳出一个小图标 并且COM Surrogate停止工作 问题事件名称 BEX 应用程序名 DllHost exe 应用程序版本 6 1 7600 16385 应用程序时间戳
  • How do I integrate my application with CXF

    http cxf apache org docs how do i integrate my application with cxf html Transports CXF支持 HTTP JMS Local等传输方式 Bindings C
  • Java文字转语音

    注意 只能在windows上使用 import com jacob activeX ActiveXComponent import com jacob com Dispatch import com jacob com Variant 文字
  • mongodb二进制操作

    https mongodb github io mongo cxx driver api legacy 1 0 4 bsonmisc 8h source html https github com waitman mongo cxx dri
  • 搜索引擎工作原理

    点击上方关注 前端技术江湖 一起学习 天天进步 作者 君额上似可跑马 https segmentfault com a 1190000019830311 搜索引擎的工作过程大体可以分为三个阶段 1 对网页进行抓取建库 搜索引擎蜘蛛通过抓取页
  • GDCM: 图像片段分割器(gdcm::ImageFragmentSplitter)的测试程序

    GDCM 图像片段分割器 gdcm ImageFragmentSplitter 的测试程序 include
  • Scala学习笔记(三)——类和对象

    3 1 类 字段和方法 类和字段与java类似 方法推荐尽量避免使用返回语句 尤其是多条返回语句 代之可以把每个方法当作是创建返回值的表达式 如下 3 2 分号推断 除非以下情况的一种成立 否则行尾被认为有分号 1 由一个不能合法作为语句结
  • 算法图解笔记(附PDF下载地址)

    算法图解笔记 分治策略 散列函数 广度优先搜索 狄克斯特拉算法 动态规划 算法图解 pdf版 链接 https pan baidu com s 1FJvija2NNmhOSpd7D3yE g 提取码 bwcm 分治策略 分治策略 分而治之
  • sqli-labs第三关

    初始页面 url入手 给个参数 id 1 回显正常 当我们给的参数是 id 1 时报错 说明他是字符型注入 原本的SQL语句加上我们给的就成了 id 1 回显报错 而且报错还多了一个括号 猜想SQL语句是这样的 select from us
  • 率先拿下512节点测试,华为GaussDB表示“很轻松”

    近日 在中国信息通信研究院和数据中心联盟发起的分布式分析型数据库测试中 华为GaussDB分析型数据库率先通过512节点集群规模能力评测 与此同时 中国某世界级银行也完成了采用华为GaussDB分布式分析型数据库对国外顶级数据仓库产品的完全
  • 每日风险投资速递(7月18日,14个互联网动态事件)

    1 传闻 阿里 魅族 传阿里9亿美元收购魅族40 股份 魅族副总裁李楠 魅族和阿里的确在酝酿合作 但融资消息并不属实 点评 顺藤摸瓜 2 动态 拍拍网 京东旗下拍拍网上线运营 对外公布在流量分发 用户分享 平台规则等多方面举措 其中PC店铺
  • 在MDK5中,warning:  #550-D: variable "d" was set but never used 的理解以及解释

    1 warning 550 D variable d was set but never used描述 变量 d 定义但从未使用 或者是 虽然这个变量你使用了 但编译器认为变量d所在的语句没有意义 编译器把它优化了 解决 仔细衡量所定义的变
  • 想跳槽涨薪的必看!2021年你与字节跳动只差这份笔记,大厂内部资料

    说白了 哪一个行业不是吃青春饭呢 无论哪个行业 大部分的从业人员都是在拿青春赌明天 而且很残忍的一个事实是 没有人的工作是不可取代的 如果你辞职 老板极力挽留 那就说明 你是那帮取代你的候选人当中最便宜的 市场在逐渐成熟 程序员的前景确实灰
  • java获取当前路径的方法

    参考网址 https www cnblogs com franson 2016 p 5728280 html 面临问题 需要在linux系统中run jar文件 运行过程包括文件IO 由于txt文件在windows系统中和在linux中路径
  • 0-1背包问题由二维数组转换为一维数组的理解

    对于0 1背包问题的话 可以使用一维数组来表示 我们要知道每一行的数据其实是依赖于上一行的数据 并不依赖于本行的数据 所以无论正序或者逆序更新一行的数据都不会需要本行的数据 但是为什么用一维数组更新时就要用逆序呢 其实是因为用一维数组更新时
  • imx8烧写Linux系统,RT-Linux在IMX8上的使用

    By Toradex胡珊逢 Real time Linux 是指在普通 Linux 内核打上 PREEMPT RT补丁后使内核满足实时要求 下面我们将使用 Apalis iMX8QM 介绍如何开启 Linux 5 4 的实时功能 首先需要下
  • 200 行代码实现一个简单的区块链

    java 区块链开发与交流群 613121183 有兴趣的也可以加下哈 提供了不少区块链资料 以后有资料可以相会共享 区块链的基础概念很简单 一个分布式数据库 存储一个不断加长的 list list 中包含着许多有序的记录 然而 在通常情况