通过创建一条链来学习区块链 (1)
通过创建区块链来学习区块链(1)
主要内容:
- Block的数据结构
- 挖矿的过程
- 工作量证明机制
- 工作量证明的简单实现
- 建立一条简单的测试链
环境:
- python 3.7
区块链本质上是一个共享数据库,存储于其中的数据或信息,具有如下特点:
- 数据仅可通过共识算法以块的形式增加,不可修改或删除,以防止篡改。
- 每个区块至少会包含一个块生成时间和出块签名。
- 所有的交易数据都会被双方签名,以防止抵赖。
- 传统区块链中,新增区块中储存上一个区块的hash,并通过此hash与上一个区块相连。
区块(Block)长什么样
Block 包含下面几个要素:
- index : 索引
- timestamp :时间戳
- transactions : 交易列表
- proof : 证明(工作量证明)通过工作量证明算法计算
- previous_hash :上一个区块的哈希值,保证了区块链的不变性
block = {'index': 1,'timestamp': 1626857298.6391933,'transactions': [{'sender': "147FA8527",'recipient': "DA5DF1FD8",'amount': 50,}],'proof': 32740,'previous_hash': "06e825e27e52f558e92f7be2f679caf101fbfe227e9cd8d80845029911a0f2d4"
}
class Blockchain
创建一个Blockchain类用来初始化区块链实例。
class Blockchain :
- 属性:
- chain : 列表记录Block
- transaction : 列表记录交易
- 方法:
- new_block() : 创建新的区块(Block)并加入链中(chain)
- new_transaction() : 添加新的交易(transaction)到交易记录中,并返回下一个区块的索引
- hash() : 生成区块的哈希值
- last_block() : 返回区块链中的最后一个块
方法的具体实现:
class Blockchain(object):def __init__(self):self.chain = []self.current_transactions = []# 初始化实例时,同时也创建一个头节点self.new_block(previous_hash = 666, proof = 888)def new_block(self, previous_hash, proof):# 创建一个新的block并添加到chain中"""previous_hash : <int>/<str> 前一个block的哈希值proof :<int> 工作量证明return -> <dict> New Block"""block = {}block['index'] = len(self.chain) + 1block['timestamp'] = time()block['transactions'] = self.current_transactionsblock['proof'] = proofblock['previous_hash'] = previous_hash or self.hash(self.chain[-1])self.chain.append(block)## clean current_transactionsself.current_transactions = []return blockdef new_transaction(self, sender, recipient, amount):# 添加新的transaction到交易列表中"""sender : <str> sender的地址recipient : <str> recipient的地址amount : <int> 数量return -> <int> 索引,是当前block的后续block的索引"""transaction = {}transaction['sender'] = sendertransaction['recipient'] = recipienttransaction['amount'] = amountself.current_transactions.append(transaction)return self.last_block['index'] + 1@staticmethoddef hash(block):# 生成block的哈希值"""block : <dict> blockreturn -> <str> 哈希值"""block_string = json.dumps(block, sort_keys=True).encode()hash_val = hashlib.sha256(block_string).hexdigest()return hash_val@propertydef last_block(self):# 返回chain中的最后一个blockreturn self.chain[-1]
Blockchain类已经实现了创建区块链的大部分功能,但是还差一个很重要的功能,那就是工作量计算和验证。从new_block()可以看出,每创建一个新的区块除了要记录一个不定长的交易列表外,还要提供一个工作量证明。了解工作量证明之前先简单说一下挖矿。
矿是怎么挖的
挖矿就是创建新的区块并添加到链上的一个过程,每当一个矿工成功创建一个区块就会获得一些加密货币作为奖励。但是在整个网络中同时有成千上万甚至几十万的矿工在挖矿,奖励有限,给谁?为了公平起见,采用了一种工作量证明机制,每个矿工在创建新区块的时候,要提供工作量证明,工作量被认可,矿工创建的区块才会被认可,并获得奖励。同时会立刻向全网广播该区块。其他矿工在收到新区块后,会对新区块进行验证,如果有效,就把它添加到区块链的尾部。在本轮工作量证明的竞争中,这个矿工胜出,而其他矿工都失败了。失败的矿工会抛弃自己当前正在计算还没有算完的区块,转而开始计算下一个区块,进行下一轮工作量证明的竞争。
工作量怎么证明的
工作量证明的本质就是计算,通过计算证明矿工的工作量,工作量证明有两个特点:
- 计算过程十分复杂
- 工作量的验证过程简单
哈希算法常被用来进行工作量证明计算,矿工就是通过不断的尝试哈希计算,直到找到了一个满足要求的哈希值,此时就算是挖矿成功了。具体的工作量证明不同的区块链略有不同,但本质都是进行哈希计算。
下面通过一个简单的例子来说明一下:
假设:当前网络中对创建新区块的要求是:哈希值的首位必须为0。为了尝试不同的哈希值,在挖矿过程中,我们采用一个变量PPP,跟前一个区块一起进行哈希计算(为了简单起见,我们只用上一个区块中的工作量证明参与哈希计算),直到得到特定的哈希值,此时那个PPP就可以作为矿工的工作量证明,否则不停的尝试新的PPP。验证的方法就是,将矿工提供工作量证明PPP跟前一个区块的工作量证明组合在一起进行哈希计算,检验哈希值是否满足要求。
举个例子,当前链中最后一个Block的工作量证明 proof = 888,下一个区块的工作量证明过程如下:
from hashlib import sha256prev_proof = 888
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[0] != "0": # 哈希值的首字符为0new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 13, new_proof : 26
经过13次的计算,就找到的满足的哈希值和新的工作量证明,下面验证工作量是否有效:
new_proof = 26sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()
>>>'06e825e27e52f558e92f7be2f679caf101fbfe227e9cd8d80845029911a0f2d4'
经过验证,工作量有效。下面继续模拟上面的过程,假设当前的要求是前两位哈希值为00:
prev_proof = 26
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[:2] != "00":new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 25, new_proof : 50
前三位哈希值为000:
prev_proof = 50
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[:3] != "000":new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 1266, new_proof : 2532
前四位哈希值为0000:
prev_proof = 2532
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[:4] != "0000":new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 6280, new_proof : 12560
前五位哈希值为00000
prev_proof = 12560
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[:5] != "00000":new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 356128, new_proof : 712256
前六位哈希值为000000:
prev_proof = 712256
new_proof = 0 # ? P
count = 0 # 记录hash的次数
while sha256(f'{prev_proof}{new_proof}'.encode()).hexdigest()[:6] != "000000":new_proof = new_proof + 2count += 1
print("count : %d, new_proof : %d"%(count, new_proof))
count : 1552855, new_proof : 3105710
从上面的模拟结果可以发现,随着网络对创建新区块的哈希值要求的变化,矿工要进行哈希计算的次数也在迅速增加,这意味着挖矿的成本也在增加。实际挖矿中,这个挖矿的难度,即哈希值前几位为0的个数会动态的调整,来保证新区块生成的效率。全网算力减少(矿工减少),难度值就会减少,反之算力增加,挖矿难度也随之增加。
工作量证明实现和验证
class Blockchain(object):def __init__(self): ...def new_block(self, previous_hash, proof): ...def new_transaction(self, sender, recipient, amount): ...@staticmethoddef hash(block):...@propertydef last_block(self): ...def proof_of_work(self, last_proof):"""POW : hash(pp')p : previous_proof, p': new_prooflast_proof: <int> 上一个区块中的proofreturn -> <int> new_proof 满足哈希条件的工作量证明"""proof = 0while self.valid_proof(last_proof, proof) is False:proof += 1return proof@staticmethoddef valid_proof(last_proof, proof):"""验证POW,hash(pp')是否满足条件0000"""guess = f'{last_proof}{proof}'.encode()hash_val = hashlib.sha256(guess).hexdigest()return hash_val[:4] == "0000"
创建一条测试链
test_chain = Blockchain()
# 链中的第一个block
test_chain.chain
[{'index': 1,'timestamp': 1626857298.6391933,'transactions': [],'proof': 888,'previous_hash': 666}]
# 记录网络中一段时间里发生的交易
test_chain.new_transaction("APPLES123","BANANA234", 111)
test_chain.new_transaction("JDI83NG0C","BANANA234", 123)
test_chain.new_transaction("APPLES123","BANANA234", 345)
test_chain.new_transaction("JDI83NG0C","BANANA234", 666)
工作量证明
# 当前链中最后一个block的工作量证明
prev_proof = test_chain.last_block['proof']
# 工作量证明的计算,返回验证通过的工作量证明
new_proof = test_chain.proof_of_work(prev_proof)
创建新的区块
# 计算链中最后一个block的哈希值
prev_hash = test_chain.hash(test_chain.last_block)
# 创建新区块并加入链中
test_chain.new_block(prev_hash, new_proof)
{'index': 2,'timestamp': 1626857779.4037974,'transactions': [{'sender': 'APPLES123','recipient': 'BANANA234','amount': 111},{'sender': 'JDI83NG0C', 'recipient': 'BANANA234', 'amount': 123},{'sender': 'APPLES123', 'recipient': 'BANANA234', 'amount': 345},{'sender': 'JDI83NG0C', 'recipient': 'BANANA234', 'amount': 666}],'proof': 124179,'previous_hash': '3c339eac60c9a4f1ee84d42a5c70bea4d510a57a80d833a2cbfc849768ec0964'}
继续添加新的区块
# 记录交易
test_chain.new_transaction("TNCSSS256","JWDLH021", 111)
# 工作量证明
prev_proof = test_chain.last_block['proof']
new_proof = test_chain.proof_of_work(prev_proof)
# 创建新区块
prev_hash = test_chain.hash(test_chain.last_block)
test_chain.new_block(prev_hash, new_proof)
{'index': 3,'timestamp': 1626858267.9535542,'transactions': [{'sender': 'TNCSSS256','recipient': 'JWDLH021','amount': 111}],'proof': 39221,'previous_hash': '0d411a993912d9e20e1ccdc670ab1b8ae2062973c5c9eddca8c47a4ad3d3c9b0'}
test_chain.chain
[{'index': 1,'timestamp': 1626857298.6391933,'transactions': [],'proof': 888,'previous_hash': 666},{'index': 2,'timestamp': 1626857779.4037974,'transactions': [{'sender': 'APPLES123','recipient': 'BANANA234','amount': 111},{'sender': 'JDI83NG0C', 'recipient': 'BANANA234', 'amount': 123},{'sender': 'APPLES123', 'recipient': 'BANANA234', 'amount': 345},{'sender': 'JDI83NG0C', 'recipient': 'BANANA234', 'amount': 666}],'proof': 124179,'previous_hash': '3c339eac60c9a4f1ee84d42a5c70bea4d510a57a80d833a2cbfc849768ec0964'},{'index': 3,'timestamp': 1626858267.9535542,'transactions': [{'sender': 'TNCSSS256','recipient': 'JWDLH021','amount': 111}],'proof': 39221,'previous_hash': '0d411a993912d9e20e1ccdc670ab1b8ae2062973c5c9eddca8c47a4ad3d3c9b0'}]
下一步:
- 创建一个web服务实现矿工节点跟区块链间的通信
- 模拟矿工跟区块链间的通信过程
通过创建一条链来学习区块链 (1)相关推荐
- 通过python构建一个区块链来学习区块链
了解区块链Blockchains如何工作的最快方法就是构建一个区块链.你来到这里是因为,和我一样,你对加密钱币的崛起感到很兴奋.而且你想知道区块链是如何工作的,想了解它们背后的基本技术. 但理解区块链 ...
- 学习区块链要掌握哪些专项能力?区块链学习培训多长时间?
2017年在北京举办的"一带一路"国际合作高峰论坛,沿线的20国青年评选出了他们心目中中国的"新四大发明":高铁.支付宝.共享单车和网购.而在这"新四 ...
- 区块链是什么?区块链能做什么?区块链学习路线分享
2017年区块链在某些领域的应用已经相当成熟,比特币(加密数字货币),以太坊(区块链开发平台),超级账本(面向企业的分布式账本平台).也有一些处在起步阶段的应用(智能合约,证券.资产管理,公证防伪,知 ...
- 怎么样才能更高效的学习区块链
一.为什么选择区块链 选择区块链作为实践学习的案例,原因有三: 第一,区块链是我最近两三个月刚学习的领域,对我来说也是一门从零开始学习的领域,这样的学习案例最具有指导作用.因为时间没有隔太久,很多学习 ...
- 区块链学习——区块链的技术栈
摘要 我在区块链学习的上一篇博文,链接:区块链学习--区块链技术理念与工作流程中,简单介绍了区块链的技术理念以及工作流程,本文我将继续介绍区块链技术栈. 我们知道,区块链本身只是一个数据的记录格式,就 ...
- 如何学习区块链技术?
2018年春节最火热的概念应该就是区块链了,从百度的莱茨狗和网易星球刷屏朋友圈,到3点钟区块链无眠群的大火,大佬们纷纷进军区块链,不了解区块链好像错过一个时代. 这里把学习区块链过程中的一些资料进行索 ...
- 如何系统学习区块链技术-干货来袭
区块链术涉及面很广,很多开发人员看了一些资料后,感觉似懂非懂. 如何系统的学习区块链技术,是很多想从事区块链开发的程序员的疑问,本文内容有点多,一次吸收不完可以收藏以后再用. 苦口婆心写在前面: 从事 ...
- 要凉?46%开发者表示短期内不考虑学习区块链技术,拿什么拯救你我的区块链人才荒...
程序员应该选择什么技术领域才能获得最高的回报? 本文详细解读了 2018 年最热门的五大领域,对行业现状.薪资概况及具体的技能要求给出了深入的分析,希望给担心"入错行"的你提供些指 ...
- 【联邦学习+区块链】FLchain: Federated Learning via MEC-enabled Blockchain Network
文章目录 1. Introduction 2. Preliminaries and Definition 3. System Model 4. Blockchain operations in FLc ...
- 该怎么学习区块链技术?
1. 入圈之前 出来学习的第一步是出来.在区块链的世界里面,链上的数据都是资产,所以骗子多,入圈的第一步当然是要保护好自己.建议在正式入圈前,先完整的阅读这个文档,这是安全大牛余弦出品,必属精品.看完 ...
最新文章
- 74. Leetcode 501. 二叉搜索树中的众数 (二叉搜索树-中序遍历类)
- AI:2020年6月21日北京智源大会演讲分享之09:20-09:40黄铁军教授《智源进展报告》
- 另一个程序正在使用此文件 进程无法访问 iis
- java 公共组件_【JAVA语言程序设计基础篇】--Swing GUI组件的公共特性
- maven error in opening zip file报错解决
- LeetCode 1864. 构成交替字符串需要的最小交换次数
- HDFS查看异常:Operation category READ is not supported in state standby. Visit
- 不定长内存池之apr_pool
- 鉴赏交流在海报设计中的作用
- java udp 流量控制_基于UDP传输协议的实现分析之流量和拥塞控制
- docker(二)基本操作
- 万年历插件软件测试,一个计算万年历的简单程序
- Flex 学习随笔 --- 找学习资料+安装环境+工具
- 电商运营学习成长目录
- SAP《MM学习指南》操作记录----仓库盘点
- 二维码内置图片,并且把二维码放在图片指定位置上,画字,设置字本地样式,二维码批量生成
- 本地搭建wooyun图片无法加载问题解决
- 通过瑞利判据对显微镜物镜进行分辨率研究
- 上层应用程序是如何访问到底层驱动程序的呢?
- maya 中切换当前渲染器的方法和设置
热门文章
- JavaSE基础篇之-Java 流(Stream)、文件(File)和IO
- mybatis注解的使用
- maven中,xml文件无法编译,想要在Java中写xml文件,需要配置xml信息,另外springBoot设置如何在资源目录下扫描xml文件
- logback.xml日志配置文件,springboot
- ue4缓存位置怎么改_[UE4]动态液体材质浅谈
- [转]nodejs Error: request entity too large解决方案
- 写高性能 Web 应用程序的 10 个技巧 转自微软资料 .
- 01-信贷路由项目架构和 rose 框架的搭建
- IAT 注入ImportInject(dll)
- 解决windows 下 mysql命令行导入备份文件 查询时乱码的问题