教学大纲
BTC 密码学原理
hash
- 1 collision resistance(抗碰撞性) : hash碰撞 大数据下hash碰撞很难
- 2 hiding(单向的) : 单向 x->H(x) 不能反向推出
1,2 结合 实现 digital commitment 数字签名 - 3 puzzle friendly : hash的预算实现是不可预测的 需要大量的算力去找nonce 已满足target
4 挖矿难 验证容易
btc中的hash函数:SHA-256 :
签名
BTC开户:创建一个 公钥和私钥的对
来源于应该非对称的解密体系:加密用公钥,解密用私钥 (我给你发信息,我用你的公钥加密,你用你的私钥解密)公钥分发,私钥保密
使用私钥做签名,其他用户用你的公钥验证,是不是你发的交易
BTC的数据结构
hash pointers
1 hash pointers hash指针 (存地址和块的hash值) hash值监测结构内容是否被篡改 区块链是一个使用了hash指针的链表
只需要记住最后的hash值就可以判断前边的更改
hash指针只能用在无环的链表上
检测恶意节点
Merkle tree 默克树
**每个区块分为块头和块身 **
- block header 有根hash值
- block body 有交易的列表
默克树的作用
1 Merkle proof 可以证明在tree中包含某个交易
btc有两种区块 全节点和轻节点
全节点 :包含block header,block body
轻节点:block header
通过Merkle proof 计算根hash 之后和自己的block header比较,如果一样就说明内容准确。
O(log(n))
根据collision resistance 性质 全节点提供的hash不能造假。
如何证明一个区块不存在?
使用 排序的默克树,将给定区块的hash计算出来
BTC协议
数字货币要解决的问题:
- 谁发行钱
- 如何验证交易的有效性
如何验证交易的有效性
每个交易分为输入和输出两部分:输入部分说明币的来源和公钥,输出部分给出收款人的hash
在比特币中交易通过脚本实现,验证交易有效性
账本内容要取得分布式共识
BTC中的共识协议 pow
要解决的问题 有的节点可能有恶意。
在之前所说的合法区块的前提下,还要保证最长合法链
btc的共识机制靠算力(hash rate)来投票 争夺记账权
谁发行钱
出块奖励(block reward)
如果分叉了,被淘汰的一方 不能获得 reward
BTC实现
没用账户的概念,必须通过utxo得到自己的余额
基于交易的账本模式:区块里记录交易信息和铸币信息
btc的全节点维护一个UTXO:unspent transaction output
UTXO
utxo集合中每个元素要给出产生这个输出交易的hash值以及他在这个交易中是第几个输出。
可以检测两次花费问题
total inputs == total outputs
节点打包交易可以获得交易费 导致inputs 不等于 outputs (很小)
一个具体的区块
一个转账交易
挖矿过程的概率分析
伯努利实验
progress free
之前的工作对现在没有影响 (挖矿公平性的保证)
BTC的总量
每21万的区块 出块奖励减少一半
btc越来越难挖到是因为出块奖励减少,btc的稀缺性的人为导致的
btc求解的puzzle只有比拼算力这一个用途
btc is secured by mining
如果记账权被坏节点得到
可不可以偷币:不能没用电子签名,诚实的节点不接受,就会接着上一个区块挖。
可不可以二次花费:
故意不包含某些交易:没意义,交易会被之后的诚实区块打包
BTC网络
- 比特币设计原则 简单,鲁棒,但 不高效
- 一个节点收到消息进行转发,并记录消息,确保不转发相同的消息,邻居节点不考虑底层的拓扑结构,是随机的,中国节点的邻居可能在美国。
- 每个节点要维护一个等待上链的集合
- 新发布的区块和新发布的交易是类似的,越大的区块传播越慢
btc-挖矿难度
H(block header) <= target
btc使用的hash算法是SHA-256 产生的hash值是256位,输出空间是2^256
挖矿难度与目标阈值target成反比
出块时间太短会出现的问题
会出现很多分叉,对于达成共识是没好处的
如何调整难度
每隔2016个区块调整一次目标阈值,约为14天调整一次
挖矿难度与目标阈值target成反比
上调和下调不能超过4倍
如果有恶意的节点不调整target怎么办:nBits域和别人不一样,别的节点不认
btc挖矿
大部分网络都是轻节点,不挖矿,只转账。
btc如何保证安全性
密码学和共识机制 密码学:没私钥就没用合法签名,前提系统中大部分节点是好节点。
挖矿设备
cpu->GPU(btc挖矿只需要整数操作,浮点数算力被浪费)->ASTC芯片(专业挖矿设备,只能挖对应的币 除非两币使用相同的mining puzzle)
矿池
矿主给矿工分配nonce和头节点的一些数据
分配收益按照每个矿工的贡献大小来分配
如何按贡献分?降低难度,只要挖到差不多的noce就可以了,证明矿工的工作量,等挖到真正的nonce时候,按工作量进行分配,矿工收入就稳定了,不需要赌了
BTC脚本
输入输出脚本的形式
形式1
形式2 最常用
形式3 对多重签名支持
上面这种方法对于用户太不友好
目前使用的方法
一种特殊的脚本格式
销毁btc的一种方法,使得钱永远花不出去
- 一些小币种需要真正方式兑换
- 将一些知识产权放入链上,任何用户都可以使用这种方法销毁一点点btc换取往区块链上写入内容的机会 proof of burn
btc分叉(fork)
情况1 区块分歧
state fork:对于一个节点后续同时挖出两个块
forking attack 分叉攻击 aeliberate fork
情况2 协议分歧
btc协议需要升级 但有些节点没有升级
protocd fork
对协议修改的内容不同分为 硬分叉 hard fork 和软分叉 soft fork
硬分叉 hard fork(永久性的分叉)
对btc的协议增加新功能,新特性时其他节点不认就会导致分叉
就会发生社区分裂,币之间相互社群不认对方挖的币,一个币分裂为两种币了
软分叉 soft fork (不会有永久性的分叉)
对btc协议加一下限制,使得原来的区块变的不合法了
**每个发布的区块中 可以有一个铸币交易coinbasetransaction 其中有一个coinbase域,这个域用来干啥,没人规定,也没人检查,一般用来当作extra nonce **
coinbase 不止8字节 后边的内容还有空余
UTXO 只存在全节点中,轻节点想查询余额只能通过全节点,无法判断真实性,就有人提出将utxo放入coinbase中,也构成一个默克树
btc历史上软分叉的例子 P2SH
btc知识点回顾
- 一个人的地址就是他公钥的hash
- 关于 proof of burn 如果这个脚本直接输出flase 为什么可以被判定为合法,进而上链,答:这个脚本是写在当前交易的输出中的 验证一个交易是否合法是运行其上一个脚本的输出和本交易的输入进行判断的,和本交易的输出无关。
- 会不会有矿工偷答案,别人发布的区块,他说是自己发布的 答:不能,区块链中一个coinbasetransaction,里边包含了谁发布的地址,根据地址进行出块奖励
- 真实的区块链上很多区块没装满
btc 匿名性
- btc账本是公开的,谁都可以查
- btc哪里破坏了匿名性:多个地址有可能被关联在一起,输入和输出地址有可能关联, 资金与现实世界转入转出时就会有可能知道谁持有
- btc只要和现实世界发生交易,很容易暴露持有者身份 如何尽量提高匿名性:
首先要解决网络层的匿名性:多路径转发
应用层的解决方法:1,将不同人的币混在一起 coin mixing
0知识证明
例如:告诉一个人这个btc账户是我的,说明我有这个账户的私钥,但是我不能把私钥告诉你用于证明,使用产生一个私钥的签名,用公钥进行验证就可以了
0知识证明的数学基础是同态隐藏
btc思考
hash指针
全节点一般将指针存在(key value)数据库中 常用的数据库是levelDB
只要有最后一个区块的hash值就可以找到整条链
区块恋
对于多人持有的账号 不要把私钥截断保存,而是要多重签名
分布式共识
分布式共识理论上是不可能的,但实际上可能,
比特币的稀缺性
量子计算会不会结束btc?
不会 会先冲击传统金融业 btc中的hash算法是sha-256
以太坊 区块链2.0
- 改变了出块时间
- 改变了mining puzzle 对内存的要求较高
- 权益证明(proof of stake)代替工作量证明(proof of work)
- 智能合约:去中心化的合约(如果是中心化合同,合同来着不同的国家就有可能没用统一的司法管辖权)
以太坊账户
- btc是基于交易的账本,没有显式的记录账户的钱,要通过utxo计算。
- 以太坊是基于账户的模型,对双花有天然的防御,缺点:有可能被重放攻击(replay attack 收钱的人不诚实)
防御方法 :加一个交易次数,转账的时候交易次数称为交易的一部分,
以太坊的账户类型
- 1.外部账户(externally owned account)类似于btc账户,一个公钥一个私钥 balance:余额 nonce:交易计数器
- 2 合约账户(smart contract)不能主动发起交易,code:代码 storage:存储状态 balance:余额 nonce:交易计数器 合约通过合约的地址调用
- eth设计账户系统是希望保存稳定,不能签了合约一会身份地址就变了
以太坊状态树
从账户地址到账户状态的映射,以太坊中账户地址是160位 一般标识为40个16进制的数。
前缀树 trie
优点
- 顺序不一样,结构也一样
- 不会hash碰撞
- 更新操作具有局部性 缺点
- 存储浪费
Patricia tree 经过了路径压缩的前缀树
对于稀疏的键值效果比较好,而以太坊的账户空间是160位也就是2^160,非常大,所以账户的稀疏的
MPT (merkle Patricia tree)
以太坊的block header 有3个根hash值
MPT :可以证明一个账户不存在
以太坊真正使用的是 modified MPT
为什么要留下之前的状态? 因为发生分叉后 需要根据前节点状态回滚。 因为eth有智能合约,经过智能合约后的数据无法推算回来。btc的交易简单可以推算回去
以太坊中代码的数据结构
block header
区块的结构
value 咋存在状态树?
只支持一种类型:nested array of bytes(字节数组) 以太坊中所有类型都要转为字符数组
交易树与收据树
- 交易树和收据树都是MPT
- 不同区块之间 状态树节点有可能共享,交易树和收据树是独立的
- 为什么状态数要保存全部账户,而交易树和收据树只需要保存这一区块的数据,因为如果要往新账户转账,节点是不知道账户是新的,所有要遍历整条链去找,才能确定是否为新账户
bloom filter
bloom filter是一种数据结构,可以高效的查找一个数据是否在一个大集合中,好处就是通过bloom filter这种结构可以快速过滤掉无关的区块
- 每个交易执行完会包含一个收据,收据中包含bloom filter记录类型地址等,发布的区块在块头有一个总的bloom filter。
- 以太坊的运行过程可以看作一个交易驱动的状态机,状态为状态树中的状态,交易为状态树中的交易
具体的数据结构
以太坊中的共识机制 GHOST协议
以太坊中出块时间快,更容易出现分叉现象,大算力更容易形成最长链,使的个体户无利可图,所以以太坊需要新协议。
ghost版本
- 一个区块最多只能包含两个叔父区块
- 隔好几个区块也叫叔父区块,并不是上一个区块的分叉
- 把叔父区块包含进来以后,不会执行其中的交易,也不检查叔父区块中交易的合法性,只检查这个叔父区块是不是合法发布的区块,只给奖励
- 节点记录叔父节点会得到 uncles reward
七代以内
挖矿算法
- ASIC resistance 避免挖矿机器专业化
- menory hard mining puzzle 设计一个对内存要求高的mining puzzle
以太坊的设计
两个数据集一大一小 小的16M的cache 大的1G dataset DAG 而且随着时间,数据集会增长
- ethash 矿工挖矿至少要1g 轻节点至少要16m验证
- 如果从工作量证明 proof of work 转为 权益证明 proof of stake 就不用挖矿了
- 以太坊采用了预挖矿 pre-mining 早期先生成一些币 不用挖就给早期开发者 pre-sale 早期为了支持开发而买的币
以太坊中难度调整算法
具体代码
拜占庭阶段挖矿难度调整的代码
权益证明 proof of stake
proof of work 太耗能
为啥要挖矿 挖矿是不是必须的
- 本质上是拼钱,钱多买的矿机多,算力大
- 所以为什么非得把钱投入矿机呢,直接把钱投入区块链,到时候比拼投资的钱数就可以了 (virtual mining)
- 权益证明是个闭环
以太坊中的基于权益的共识机制 (准备采用)
Casper the Friendly Finality Gadget (FFG)
- 过渡阶段也是和工作量证明一起用
- validator 验证者(需要有保证金) 用来协助系统达成共识,投票决定哪个链是最长合法链,投票权重是保证金比重,每次投票需要2/3的检验者。
- 每完成100个区块 当成一个epoch
每个验证者有一定的任期,任期结束后有一定时间的等待期,等待期过了 验证者可以获得之前的保证金和奖励
智能合约
如果转账对象是普通用户,则就是普通转账,如果转账对象是一个合约地址,则是对合约的一次调用。
转账金额可以为0,但是汽油费要给 汽油费给的是矿工
在合约中调用合约
这种方法如果被调用合约出错,则调用的合约也会出错
使用call 不会因为调用合约的出错导致主函数出错
fallback函数
智能合约的创建
汽油费
智能合约是图灵完备的
以太坊中的交易执行起来具有原子性,执行的过程中如果出错会导致整个交易回滚。消耗掉的gas不退
错误处理
gaslimit 每个矿工可以调整1/1024大小 上调和下调都可以
- 区块链的工作原理:发布一个交易,所有全节点都要先运行这个交易,同步状态
- 汽油费是怎么扣除的:每个全节点在本地维护3棵树 状态树,交易树 收据树,全节点接受到交易信息,就会在本地对数据进行更新,所有多个全节点运行交易,并不会导致账户多次扣除gas
- 先挖矿还是先执行智能合约:先执行交易,再挖矿,因为没用3棵树的hash 就不能得到头hash
- 没挖到区块的全节点:不会给任何补偿,无gas费,而且还有把他人发布的区块上的交易(发布的区块里没有具体的3棵树的状态,节点想获得最新的状态必须验证交易),全执行一遍,得到3棵树,进行验证发布的区块是否合法
- 错误的智能合约要不要发布到区块上:也要,因为要扣除gas
- 智能合约是否支持多线程:不支持多线程 没用并发执行!
一个智能合约的例子
写一个智能合约然后发布到0x0地址 交易费为0,gas要给,矿工把交易上链后返回给你一个合约地址地址,每次的竞拍存在智能合约这个账户的状态信息中,外部账户出价调用bid函数,也是一次交易,也被写在链上
有可能被攻击,导致大家的钱都缩在里边。
code is law 规则中有问题,就不能改了,有可能直接把钱锁在合约里,永远拿不出来
拍卖版本2.0
会被重入攻击
send函数 转账发送给调用合约的gas只要2300个,只够写一个log,不够第二次攻击
TheDAO
DAO(decentralized Autonomous Organization) 去中心化的组织
- 组织的规章制度写在代码中
- TheDAO是一个组织名 投资组织,将钱给这个合约组织,大家投票决定如何投资
- splitDAO:取钱,并且获得childDAO 相当于拆分TheDAO splitDAO代码
反思
- 智能合约真的智能吗?其实可以叫做自动合约:类似于ATM
- 不可篡改性其实是双刃剑
- 不可篡改性不是绝对的
- solidity这个语言存在一些问题
- 通过模板保证智能合约的安全性
- 以太坊硬分叉是一种中心化行为吗? 其实硬分叉成功是绝大多少矿工的支持,存在分叉的选项恰恰是去中心化的体现
- 分布式 != 去中心化 分布式 每台计算机执行不同任务 是为了得到类似于线性加速的性能提升,而去中心化的状态机其实是为了容错,每台机器执行相同的任务,效率低 还不如一台机器
- 智能合约是用来编写控制逻辑的,不要计算服务
美链
做运算的时候要注意小心溢出
不存在精度损失