【区块链Go语言实现】Part 1:区块链基本原型
0x00 介绍
区块链(Blockchain)是21世纪最具革命性的技术之一,目前它仍处于逐渐成熟阶段,且其发展潜力尚未被完全意识到。从本质上讲,区块链只是一种记录的分布式数据库。但它之所以独特,是因为它并不是一个私有的数据库,而是一个公共数据库,也就是说,每个使用它的人都有一份完整或部分的数据副本。并且,只有在数据库的其他持有者同意的情况下,才可以向区块链中添加新的记录。此外,正是区块链使得加密货币和智能合约成为可能。
在本系列文章中,我们将基于区块链构建一种简单的加密货币。
0x01 区块
首先,我们从“区块链”中的“区块”介绍开始。在区块链中,区块是存储有价值信息的块。例如,比特币区块用于存储交易,这是任何一种加密货币的本质。除此之外,区块还包含一些技术信息,比如它的版本、当前时间戳和前一区块的散列值(哈希值)。
在本文中,我们不打算实现区块链或比特币规范中描述的那种区块,而是使用它的简化版本,即我们将要实现的区块结构中只包含重要的信息。下面代码中为我们的区块结构:
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
}
Timestamp(时间戳)是区块创建时刻的时间戳,Data是包含在区块中的实际有价值的信息,PrevBlockHas存储前一区块的散列值,而Hash是当前区块的散列值。在比特币规范中,Timestamp、PrevBlockHash和Hash是区块头,它们组成了一个单独的数据结构,而交易(在我们的例子中是Data)也是一个单独的数据结构。为了简单起见,我们此处将它们混合在一起。
那么如何计算散列值呢?散列值的计算方式是区块链的一个十分重要的特性,正是该特性使得区块链变得安全。计算一个区块的散列值是一种计算上十分困难的操作,即使在快速计算机上也需要一些时间(这就是人们会购买强大的GPU来挖比特币的原因)。这是一种有意的架构设计,它使得添加新的区块变得很困难,因此可以防止对已有区块的篡改。我们将在以后的文章中讨论并实现这种机制。
现在,我们仅仅使用区块字段,连接它们,并在连接的组合上计算一个SHA-256散列值。下面,我们使用SetHash方法来实现这一操作:
func (b *Block) SetHash() {
timestamp := []byte(strconv.FormatInt(b.Timestamp, ))
headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{})
hash := sha256.Sum256(headers) b.Hash = hash[:]
}
接下来,依照Golang惯例,我们将实现一个函数来简化区块的创建:
func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
block.SetHash()
return block
}
这样,我们就准备好了区块的工作!
0x02 区块链
现在,我们来实现一个区块链。实质上,区块链只是一个包含某些特定结构的数据库:它是一种有序的反向链接列表。这意味着区块以插入顺序进行存储,并每个区块会链接到前一区块。这个结构能够保证快速获得一个区块链中最新的区块,并能够通过区块散列值高效地获取到该区块。
在Golang中,可以使用一个数组和一个map来实现这种结构:数组用于保存有序的散列(在Go中数组是有序的),而map用于保存散列->区块对(map是无序的)。然而,对于我们的区块链原型来说,我们仅仅使用一个数组,因为现在我们不需要通过区块的散列来获得对应的区块。
type Blockchain struct {
blocks []*Block
}
这是我们的第一个区块链,我从未想过它会这么容易。
现在我们实现添加区块的功能:
func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.blocks[len(bc.blocks)-]
newBlock := NewBlock(data, prevBlock.Hash)
bc.blocks = append(bc.blocks, newBlock)
}
这样就完了么?No!
为了向区块链中添加一个新区块,我们需要确保已经存在了一个区块,但是目前我们的区块链中并未存在任何区块。所以,在任何区块链中,都必须存在至少一个区块,区块链中的首个区块称为创世区块。下面,我们实现一个方法来创建创世区块:
func NewGenesisBlock() *Block {
return NewBlock("Genesis Block", []byte{})
}
现在,我们可以实现一个函数来使用创世区块创建一个区块链:
func NewBlockchain() *Blockchain {
return &Blockchain{[]*Block{NewGenesisBlock()}}
}
下面,我们来检查一下我们的区块链是否能够正常工作:
func main() {
bc := NewBlockchain() bc.AddBlock("Send 1 BTC to Ivan")
bc.AddBlock("Send 2 more BTC to Ivan") for _, block := range bc.blocks {
fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("Hash: %x\n", block.Hash)
fmt.Println()
}
}
输出结果如下:
Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168 Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Send BTC to Ivan
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1 Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Send more BTC to Ivan
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1
通过上面的结果,我们可以确定该区块链可以正常工作。
0x03 结论
本文中,我们创建了一个非常简单的区块链原型:它仅仅是一个区块数组,其中每个区块都有一个链接到前一区块,不过实际的区块链要比这复杂得多。在我们的区块链中,添加新的区块简单快速,但在实际的区块链中添加新区块则需要做一些工作:在获取添加区块的权限之前,区块添加者(或者说节点)必须执行一些繁重的计算(这种机制称为工作证明,Proof-of-Work,POW)。此外,区块链是一种分布式数据库,所以并没有一个唯一的决策者。因此,一个新的区块必须由网络中的其他参与者确认和批准(这种机制称为共识机制)。最后,目前我们的区块链中还没有交易!在后续的文章中我们将逐步讨论这些功能和特点。
下一篇《【区块链Go语言实现】Part 2:工作量证明机制POW》中我们将介绍区块链中的工作量证明机制。
英文链接:https://jeiwan.cc/posts/building-blockchain-in-go-part-1/
【区块链Go语言实现】Part 1:区块链基本原型的更多相关文章
- 【区块链Go语言实现】Part 2:工作量证明机制POW
0x00 介绍 在上一篇文章中,我们建立了一个非常简单的数据结构,它是区块链数据库的本质.并且,我们实现了以类似链条关系的方式向其中添加区块的功能:每个区块都会链接到前一区块.然而,我们实现的区块链有 ...
- 区块链--Ubuntu上搭建以太坊私有链
1.搭建私链所需环境 操作系统:ubuntu16.04,开虚拟机的话要至少4G,否则会影响测试挖矿时的速度 软件: geth客户端 Mist和Ethereum Wallet:https://githu ...
- 启迪链网通证经济共同体:柏链教育&火聘online推出区块链行业人才“一门式”服务
近日,启迪链网通证经济共同体旗下两个节点成员柏链教育与火聘online,达成节点间的合作,据悉本次合作是采用共同体的生态共建模式,柏链教育与火聘online共享企业端岗位需求的大数据,然后有针对性的开 ...
- CN109241772A发票区块链记录方法、装置、区块链网关服务器和介质(腾讯)
学习笔记-2 CN109241772A发票区块链记录方法.装置.区块链网关服务器和介质(腾讯) 解决什么问题? 让发票信息记录到区块链的情况下减少发票信息泄露 链上有什么数据? 发行发票事件信息(发票 ...
- 小甲鱼PE详解之区块表(节表)和区块(节)续(PE详解05)
这一讲我们结合实例来谈谈区块表的定义以及各个属性的含义. 首先,我们先用之前学过的一点知识在二进制文件中手动翻找区块表,这样做的好处是可以使你很快的对PE结构牢记于心.学来的东西就是能用的东西,不能用 ...
- 【树链剖分】洛谷P3379 树链剖分求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- AntShares区块链的节点部署与搭建私有链
近期陆续体验常见的区块链开源项目,比如小蚁OnChain出的AntShares.AntShares跟其它开源区块链项目不一样,他们家是使用C#开发,基于.NET Core执行在Linux,期待未来出G ...
- 区块链中的密码学(-)区块链中运用最广的散列算法-SHA256算法分析与实现
在很多技术人员的眼中,区块链并不是一种新的技术,而是过去很多年计算机技术的组合运用.而在这个方方面面技术的运用上,基于密码学的加密算法可以说是区块链各种特点得以表现的根本,一旦目前使用的加密算法被证实 ...
- 区块链入门(2):搭建以太坊私有链(private network of ethereum),以及挖矿的操作..
在做一些测试工作的时候, 为了方便控制以及更快的进入真正的测试工作,可能需要搭建一个私有的以太坊网络. 而以太坊节点之间能够互相链接需要满足1)相同的协议版本2)相同的networkid,所以搭建私有 ...
随机推荐
- 3.Ubuntu下安装mysql并在windows下使用Navicat来连接
一.安装mysql(只需要三条命令) 1.第一条命令(中间需要输入root用户密码): sudo apt-get install mysql-server 2.第二条命令: sudo apt-get ...
- hdu 1.2.7
#include<cstdio> #include<iostream> using namespace std; int main() { //freopen("in ...
- PSP个人项目耗时对比记录表:四则运算
Personal Software Process Stages Time(%) 计划 5 •估计这个任务需要多长时间 5 开发 60 •需求分析 5 •生成设计文档 5 ...
- 使用HAProxy实现sql server读库的负载均衡
前置条件 使用sqlserver的发布订阅功能实现读写分离,并创建多个读库. 本文的负载均衡是针对多个读库而言的. 测试环境 vmware 10 64位 windows server 2008 R2 ...
- 安装使用Entity Framework Power Tool Bate4 (Code First)从已建好的数据自动生成项目中的对应Model(新手贴,望各位大侠给予指点)
从开始学习使用MVC以后,同时也开始接触EF,很多原理都不是太懂,只知道安装了EF以后,点击哪里可以生成数据库对应的Model,不用再自己手写Model.这里记录的就是如何从已建立好的数据库生成项目代 ...
- DotNetCore依赖注入实现批量注入
文章转载自平娃子(QQ:273206491):http://os.pingwazi.cn/resource/batchinjectservice 一.依赖注入 通过依赖注入,可以实现接口与实现类的松耦 ...
- [WPF]为旧版本的应用添加触控支持
之前做WPF开发时曾经遇到这样一个需求:为一个基于 .NET Framework 3.5开发的老旧WPF程序添加触控支持,以便于大屏触控展示. 接手之后发现这是一个大坑. 项目最初的时候完全没考虑过软 ...
- [Ynoi2016]这是我自己的发明(莫队)
话说这道题数据是不是都是链啊,我不手动扩栈就全 \(RE\)... 不过 \(A\) 了这题还是很爽的,通过昨晚到今天早上的奋斗,终于肝出了这题 其实楼上说的也差不多了,就是把区间拆掉然后莫队瞎搞 弱 ...
- PANIC: Missing emulator engine program for 'x86' CPU.
获取可用的Android模拟器 1:emulator -list-avds 获取可用的模拟器的名称(只用名称) 2: android list -avd 获取可用的模拟器(信息详细) 获取iO ...
- postgresql和redis
redis 和postgresql区别以及其优缺点 一刹那者为一念,二十念为一瞬,二十瞬为一弹指,二十弹指为一罗预,二十罗预为一须臾,一日一夜有三十须臾. 那么,经过周密的计算,一瞬间为0.36 秒, ...