Submitted by admin on 2017, February 10, 3:55 PM
golang 的 select 的功能和 select, poll, epoll
相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。
示例:
ch1 := make (chan int, 1) ch2 := make (chan int, 1) ... select { case <-ch1: fmt.Println("ch1 pop one element") case <-ch2: fmt.Println("ch2 pop one element") }
注意到 select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是【IO 操作】 。
此示例里面 select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据。 则 select 语句结束。
【使用 select 实现 timeout 机制】
如下:
timeout := make (chan bool, 1) go func() { time.Sleep(1e9) // sleep one second timeout <- true }() ch := make (chan int) select { case <- ch: case <- timeout: fmt.Println("timeout!") }
当超时时间到的时候,case2 会操作成功。 所以 select 语句则会退出。 而不是一直阻塞在 ch 的读取操作上。 从而实现了对 ch 读取操作的超时设置。
下面这个更有意思一点。
当 select 语句带有 default 的时候:
ch1 := make (chan int, 1) ch2 := make (chan int, 1) select { case <-ch1: fmt.Println("ch1 pop one element") case <-ch2: fmt.Println("ch2 pop one element") default: fmt.Println("default") }
此时因为 ch1 和 ch2 都为空,所以 case1 和 case2 都不会读取成功。 则 select 执行 default 语句。
就是因为这个 default 特性, 我们可以使用 select 语句来检测 chan 是否已经满了。
如下:
ch := make (chan int, 1) ch <- 1 select { case ch <- 2: default: fmt.Println("channel is full !") }
因为 ch 插入 1 的时候已经满了, 当 ch 要插入 2 的时候,发现 ch 已经满了(case1 阻塞住), 则 select 执行 default 语句。 这样就可以实现对 channel 是否已满的检测, 而不是一直等待。
比如我们有一个服务, 当请求进来的时候我们会生成一个 job 扔进 channel, 由其他协程从 channel 中获取 job 去执行。 但是我们希望当 channel 瞒了的时候, 将该 job 抛弃并回复 【服务繁忙,请稍微再试。】 就可以用 select 实现该需求。
关于垃圾回收
c++
写久了的人, 刚接触 golang 的时候最不能理解的就是为什么作者要支持垃圾回收。 不管是从垃圾回收器的实现上看, 还是对于程序员编程习惯的养成方面, 都避免不了编写出的程序性能损失。 但是写了几天 golang 之后, 又觉得有垃圾回收确实大大减轻程序员的心智负担, 降低编程门槛,提高编程效率。 让我联想到 汇编 和 C语言 的关系, 即使 C语言的性能不如汇编写出来的高, 但是后者还是颠覆了前者。
golang | 评论:0
| Trackbacks:0
| 阅读:521
Submitted by admin on 2017, February 10, 3:33 PM
刚才看golang的sync的包,看见一个很有用的功能。就是WaitGroup。
先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
这里要注意一下,他们的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。
WaitGroup总共有三个方法:Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。
Add:添加或者减少等待goroutine的数量
Done:相当于Add(-1)
Wait:执行阻塞,直到所有的WaitGroup数量变成0
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0 ; i > 5 ; i = i + 1 {
wg.Add( 1 )
go func(n int ) {
defer wg.Add(- 1 )
EchoNumber(n)
}(i)
}
wg.Wait()
}
func EchoNumber(i int ) {
time.Sleep(3e9)
fmt.Println(i)
}
|
golang中的同步是通过sync.WaitGroup来实现的.WaitGroup的功能:它实现了一个类似队列的结构,可以一直向队列中添加任务,当任务完成后便从队列中删除,如果队列中的任务没有完全完成,可以通过Wait()函数来出发阻塞,防止程序继续进行,直到所有的队列任务都完成为止.
WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,而不需要sleep一个固定的时间来等待.但是其缺点是无法指定固定的goroutine数目.但是其缺点是无法指定固定的goroutine数目.可能通过使用channel解决此问题。
另一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package main
import (
"fmt"
"sync"
)
var waitgroup sync.WaitGroup
func Afunction(shownum int ) {
fmt.Println(shownum)
waitgroup.Done()
}
func main() {
for i := 0 ; i < 10 ; i++ {
waitgroup.Add( 1 )
go Afunction(i)
}
waitgroup.Wait()
}
|
http://studygolang.com/articles/2027
golang | 评论:0
| Trackbacks:0
| 阅读:567
Submitted by admin on 2017, January 10, 7:27 PM
SSDP 简单服务发现协议,是应用层协议,是构成UPnP(通用即插即用)技术的核心协议之一。它为网络客户端(network client)提供了一种发现网络服务(network services)的机制,采用基于通知和发现路由的多播方式实现。

SSDP多播地址:239.255.255.250:1900(IPv4),FF0x::C(IPv6)
两种类型的SSDP请求消息会通过SSDP多播地址发送:
1. 发现请求(Discovery request 或查询请求)。SSDP客户端向此地址发送HTTP UDP 发现请求,查询某种类型的服务。SSDP服务在此地址上监听服务发现请求。当服务监听到的HTTP UDP 发现请求和它自己提供的服务匹配时,它以单播方式发送HTTP UDP 响应。
2. 存在通知(notification)。SSDP服务向此多播地址发送HTTP UDP 通知消息来宣布自己的存在。
发现结果(discovery results)和存在通知消息(presence announcements)提供的信息包括:
服务的类型URI
服务名称USN:唯一标识一种服务实例。
位置信息:发现结果和存在通知可包含一个或多个位置URI,客户端利用位置信息可以找到它需要的服务。
期限信息:客户端在自己的cache中保存此服务多长时间。如果期限过了,关于此服务的信息会被从cache中拿掉。当客户端接收到的发现结果或存在通知包含的USN和cache中的某条匹配,则更新。
客户端的服务缓存像下面这样:

【SSDP发现请求】ssdp:discover
ssdp:discover 必须包含一个ST头,客户端使用ST头来表明他们想发现的服务类型。ssdp:discover 必须包含一个带 * 的请求URI。
M-SEARCH * HTTP/1.1
S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6
Host: 239.255.255.250:1900
Man: "ssdp:discover"
ST: ge:fridge
MX: 3
各HTTP协议头的含义:
HOST:设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6)
MAN:设置协议查询的类型,必须是:ssdp:discover
MX:设置设备响应最长等待时间。设备响应在0和这个值之间随机选择响应延迟的值,这样可以为控制点响应平衡网络负载。
ST:设置服务查询的目标,它必须是下面的类型:
-ssdp:all 搜索所有设备和服务
-upnp:rootdevice 仅搜索网络中的根设备
-uuid:device-UUID 查询UUID标识的设备
-urn:schemas-upnp-org:device:device-Type:version 查询device-Type字段指定的设备类型,设备类型和版本由UPNP组织定义。
-urn:schemas-upnp-org:service:service-Type:version 查询service-Type字段指定的服务类型,服务类型和版本由UPNP组织定义。
SSDP服务发现自己的服务类型和ST中指明的服务类型匹配时,可以向ssdp:discover来自的IP地址/端口响应。响应消息应该包含服务的位置信息(Location 或AL头),ST和USN头。响应消息应该包含cache控制信息(max-age 或者 Expires头),如果两者都包含了,Expires 头优先,如果两者都缺失,那么这条服务消息不能被cache。
HTTP/1.1 200 OK
S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6
Ext:
Cache-Control: no-cache="Ext", max-age = 5000
ST: ge:fridge
USN: uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6
AL: <blender:ixl><http://foo/bar>
各HTTP协议头的含义简介:
CACHE-CONTROL:max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在
DATE:指定响应生成的时间
EXT:向控制点确认MAN头域已经被设备理解
LOCATION:包含根设备描述得URL地址
SERVER:饱含操作系统名,版本,产品名和产品版本信息
ST:内容和意义与查询请求的相应字段相同
USN:表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。
【SSDP存在通知消息】
SSDP服务通过存在通知消息来向客户端宣布自己的存在,更新期限信息,更新位置信息。
ssdp:alive 消息必须将 NT 设置成自己的服务类型,USN头设置成自己的USN。ssdp:alive 应该包括Location或者AL头,如果没有DNS支持的话,使用SSDP服务的IP地址来代表位置。ssdp:alive还应该包括cache控制信息,max-age或者Expires头。
NOTIFY * HTTP/1.1
Host: 239.255.255.250:reservedSSDPport
NT: blenderassociation:blender
NTS: ssdp:alive
USN: someunique:idscheme3
AL: <blender:ixl><http://foo/bar>
Cache-Control: max-age = 7393
ssdp:alive 没有响应消息。
SSDP服务可以发送ssdp:byebye 来宣布自己下线。ssdp:byebye 必须将NT设置成自己的服务类型,将USN头设置成自己的USN。ssdp:byebye 也没有响应消息。当客户端接收到ssdp:byebye 消息,删掉cache里面的相关条目。
NOTIFY * HTTP/1.1
Host: 239.255.255.250:reservedSSDPport
NT: someunique:idscheme3
NTS: ssdp:byebye
USN: someunique:idscheme3
【SSDP Auto-Shut-Off Algorithm】
A mechanism is needed to ensure that SSDP does not cause such a high level of traffic that it overwhelms the network it is running on.
【ssdp:all】
A mechanism is needed to enable a client to enumerate all the services available on a particular SSDP multicast channel/port.
【参考】
SSDP 协议原文:http://tools.ietf.org/html/draft-cai-ssdp-v1-03
http://www.cnblogs.com/debin/archive/2009/12/01/1614543.html
传输协议 | 评论:0
| Trackbacks:0
| 阅读:646
Submitted by admin on 2017, January 10, 6:44 PM
SSDP协议基础详解
SSDP协议,不知道大家是否听说过呢?这个协议的使用多出现在端口当中。下面我们就来了解一下这个协议的具体内容吧。什么是SSDP协议呢?SSDP就是简单服务发现协议(SSDP,Simple Service Discovery Protocol)是一种应用层协议,是构成通用即插即用(UPnP)技术的核心协议之一。
简单服务发现协议提供了在局部网络里面发现设备的机制。控制点(也就是接受服务的客户端)可以通过使用简单服务发现协议,根据自己的需要查询在自己所在的局部网络里面提供特定服务的设备。设备(也就是提供服务的服务器端)也可以通过使用简单服务发现协议,向自己所在的局部网络里面的控制点宣告它的存在。
实现
简单服务发现协议是在HTTPU和HTTPMU的基础上实现的协议。
按照协议的规定,当一个控制点(客户端)接入网络的时候,它可以向一个特定的多播地址的SSDP端口使用M-SEARCH方法发送“ssdp:discover”消息。当设备监听到这个保留的多播地址上由控制点发送的消息的时候,设备会分析控制点请求的服务,如果自身提供了控制点请求的服务,设备将通过单播的方式直接响应控制点的请求。
类似的,当一个设备接入网络的时候,它应当向一个特定的多播地址的SSDP端口使用NOTIFY方法发送“ssdp:alive”消息。控制点根据自己的策略,处理监听到的消息。考虑到设备可能在没有通知的情况下停止服务或者从网络上卸载,“ssdp:alive”消息必须在HTTP协议头CACHE-CONTROL里面指定超时值,设备必须在约定的超时值到达以前重发“ssdp:alive”消息。如果控制点在指定的超时值内没有再次收到设备发送的“ssdp:alive”消息,控制点将认为设备已经失效。
当一个设备计划从网络上卸载的时候,它也应当向一个特定的多播地址的SSDP协议端口使用NOTIFY方法发送“ssdp:byebye”消息。但是,即使没有发送“ssdp:byebye”消息,控制点也会根据“ssdp:alive”消息指定的超时值,将超时并且没有再次收到的“ssdp:alive”消息对应的设备认为是失效的设备。
在IPv4环境,当需要使用多播方式传送相关消息的时候,SSDP一般使用多播地址239.255.255.250和UDP端口号1900。
根据互联网地址指派机构的指派,SSDP字而已在IPv6环境下使用多播地址FF0X::C,这里的X根据scope的不同可以有不同的取值。
传输协议 | 评论:0
| Trackbacks:0
| 阅读:554
Submitted by admin on 2017, January 10, 2:21 PM
区块链的技术发展一日千里,几乎每天都有区块链技术或应用的新消息和进展,每个月都有新的区块链相关技术出来,各类区块链技术体系层出不穷,除了Elwin在《区块链主流开源技术体系介绍》提到的目前几大主流的开源区块链技术体系(包括比特币体系、以太坊、fabric、比特股、公证通、瑞波、未来币、锯齿湖、布比、小蚁等技术体系介绍,有兴趣可以搜索旧文看看)在不断完善发展外,市场上很快又涌现了很多新生代的区块链技术体系,本文将会一一进行介绍。
一、恒星网络
恒星网络,stellar,一个由前瑞波(Ripple)创始人Jed McCaleb发起的区块链接项目,用于搭建一个数字货币与法定货币之间传输的去中心化网关。最近,乐视金融与恒星基金会签约,共建NBiLe与Lumens两个平行网络,实现通缩与通胀并行。
恒星网络是基于Ripple基础上进行开发,在比特币和瑞波的技术基础上做了的很多改进,特别是相关的共识机制和验证算法,恒星网络运行节点性能得到提高,并节点资源需求非常低。众多改进其中,最大改动的是恒星支付系统的支撑算法SCP(恒星共识协议),号称是目前最安全的类拜占庭算法。SCP共识机制应用“集合块”,即各节点选择其可信任的其他节点。所有这些个体选择之和便是系统层面的共识集合。这些集合块将整个系统联结起来,正如个体网络的决策统一了互联网一样。SCP对计算能力以及经济成本消耗要求适度,降低了进入门槛并潜在地把金融系统开放给新的参与者,同时也是一种最佳的对抗恶性行为参与者使得系统恢复的构建方法。
开源代码地址为https://github.com/stellar/stellar-core,系统主要开发语言为C++,共识机制为SCP,支持智能合约,适用于公链和联盟链。
二、Tendermint
美国公司推出的Tendermint作为第二代区块链架构,已经超越了受限制的基于代币/类比特币的单片系统,是第一个实施分片技术的公共区块链。
Tendermint是一种开源的区块链套接字协议,消除了区块链之前的复杂性,为区块链开发提供了模块化结构,并且在区块链核心提供了一个开源的区块链引擎,使得各种机构和开发团队都能够轻松且高效地创建属于他们自己的区块链技术。Tendermint主核心将会管理所有的区块链分区,你可以有比特币分区或以太坊分区,具有很大的灵活性。在Tendermint平台上可以搭建基于任何编程语言的应用开发界面,主核心管理所有分片,分片包含很多类型,可以是比特币分片、或者以太坊分片。
Tendermint共识引擎通过Tendermint套接字协议(TMSP)与应用程序进行连接。Tendermint通过在应用程序进程和共识形成过程之间设置一个非常简单的应用程序接口,可以对区块链设计进行分解。并且TMSP不依赖于某一特定的编程语言,所以开发人员可以使用任意一种编程语言来编写智能合约。用户同样还能够利用现有的代码库,工作流和开发生态系统来创建复杂的应用程序。
开源代码地址为https://github.com/tendermint/tendermint,系统主要开发语言为GO,所使用的是拜占庭容错共识机制,支持智能合约,具有去中心化控制、低延时、渐进安全的特效,大大提高扩展性和速度,每秒钟可以完成超过10,000笔交易,适用于公链和联盟链、私链。
三、Openchain
Openchain是由区块链技术公司Coinprism开源分布式总账区块链工具,主要提供给大型企业和金融机构,Openchain 在处理大型企业和金融机构的数据的时候,相较于传统的区块链工具,能大大的降低计算速度,并能降低成本和交易方风险。
不同于比特币,Openchain基于一种独特的分布式账本技术,它可帮助用户部署自己版本的区块链,减少用户的交易成本和结算时间。Openchain去除了区块,交易和交易之间直接连通,这意味着交易可以得到即时确认。任何人都可以连接到一个验证的节点,并收到一份交易验证的实时复制本,Openchain还通过数字签名来保护交易的安全性,使交易不可伪造。另外,通过挂钩模块,基于Openchain的token可以作为侧链挂钩到比特币网络上。
开源代码地址为https://github.com/openchain/,系统主要开发语言为C#开发,他是DNX应用,可以支持跨平台运行,支持智能合约,适用于联盟链。
四、多链MultiChain
多链Multichain,他是一个区块链软件平台,任何人都可以在上面创建和部署私链(permission chain)。隐私与控制的争议是比特币成为行业性金融机构的障碍,而用MultiChain创建的私有链则克服了这个困难。Multichain支持快速部署,两步就可以生成自已的区块链,三步就可以连接上其它区块链。
MultiChain是采用PoW共识机制,通过对用户权限的综合管理解决了挖矿,隐私和公开性问题。MultiChain提供了一种创新性的可信决策网络实体的方法来解决私有区块链的挖矿问题。该平台可将挖矿活动限制在一套可供验证的实体内,并且避免了单一方对挖矿过程的垄断。这种被成为“多样性挖矿”的方案通过限定给定窗口内同一矿工的区块数量来解决挖矿问题。“多样性挖矿”取消了工作量证明的重要性和本地加密货币的必要性,并且可使处理交易的矿工以随机轮转的方式认可交易。
MultiChain向后兼容比特币,因此用户能够把现存的比特币应用导入到 MultiChain。不是支持像比特币内核的单一链, MultiChain可被配置以同时支持同一网络的不同区块链。MultiChain能够支持很多第三方资产,能够使私有区块链和比特币区块链相互转换。
MultiChain开源代码即将发布中。
五、Corda
R3的区块链软件Corda,旨在为参与其中的70多家银行研发解决方案,专为金融服务所设计的新分散式的分类帐平台。他号称自己不是区块链,而用以记录和管理金融合约的分布式账本。但Elwin认为,Cordar的系统核心还是是基于区块链技术的,他包含区块链的五大特性,共识、有效性、唯一性、不可更改性和认证,Corda採用许多区块链技术的优势与特性,同时捨弃掉让区块链技术无法融进大多数金融领域的设计理念,排除了一些不适合银行业应用场景的设计思路。
Corda平台基于产业标准工具所打造,不包含原生虚拟货币,主要特性包括能可支援各种共识机制、自动编排跨组织之间的工作流,不需仰赖单一中心化的控制机构,Corda用非常精确的时间界限来处理交易而非区块挖掘时平均大致的时间界限,且能直接设计出负责监管与监督观察作业的节点,并经由特定交易方来验证,不需由一大群与该交易无关的验证者。
Corda在智能合约,数据处理等方面也做了创新,而且也符合通过协作以保持金融数据协议的准确和共享。自然隐私和监管也在它的专用平台设计之中。Corda关注可互操作性和增量部署,不对第三方泄露机密信息。公司可以查看与对手方达成的协议,并确保双方看到的信息一致并向监管机构报备。Corda系统引入了法律语言体系,并包含管理金融协议的作用,该系统必须使企业逻辑编写简单化并与现有代码兼容,还必须支持协议相关企业间的行为协调。
针对金融使用场景和面向银行为主要使用者,Corda系统主要特点:
l 没有多余的全局数据共享:只有有合法需求的参与方可以按照协议获取数据;
l Corda编写和配置在企业间流转,无中心控制者;
l Corda在企业间单个交易水平达成共识,而不是在系统水平上;
l 系统设计直接支持监管观察员节点;
l 交易直接由交易双方验证,而不是由一大群不相干的验证者进行;
l 支持多种共识机制;
l 记录了智能合约代码和人类语言法律文件的清晰联系;
l 用行业标准工具创建;
l 没有原始加密货币。
Corda适用于联盟链,特别为金融业务打造,下个月将发布开源代码。
六、龙链
龙链(Dragonchain)是迪士尼打造的,他是将其混合公有/私有区块链的区块链平台。
龙链是另一种用来保持记录和处理交易的区块链。它与比特币的底层技术十分相似,但又有一点不同。龙链是一种多币制的区块链,节点就可以随之定义一种货币并支持其使用。该网络上可以同时使用多种货币。龙链的共识机制可以支持一种或多种现有的共识机制(Trust,PoW,PoS),甚至是可以支持自己定义和创建一种新的共识机制。
龙链的目标特性:
l 易于集成现有的系统
l 便于传统的工程师和程序员开发,不一定需要熟悉的区块链、分布式系统和密码密码学技术
l C/S客户服务器方式和RESTful方式集成
l 简单灵活的架构
l 默认情况下提供对业务数据的保护
l 允许业务集中控制过程
l 固定长度和周期,短和高速的区块
l 多货币支持
l 没有基础货币
l 与其他公共和私人blockchains的互操作性
开源代码地址为https://github.com/dragonchain/dragonchain,系统主要开发语言是Python,支持智能合约,适合联盟链和私链。
七、量子链
量子链Qtum是中国社区原创的区块链公链。Qtum通过价值传输协议(Value Transfer Protocol)来实现点对点的价值转移,并根据此协议,构建一个支持多个行业的(金融、物联网、供应链、社交游戏等)去中心化的应用开发平台(DAPP Platform)。
量子链的定位是,做一个符合行业监管的区块链去中心化应用开发平台。为了符合以后的行业监管,量子链团队在设计的时候,为监管者的角色设计了很多可选项,引入数字身份和第三方征信平台,设计一种新的合约类型—主控合约,把监管者的角色引入,同时监管者可以作为 Qtum系统中的喻言和数据源的提供者。
量子链采用可插拔的共识机制:Qtum系统包括 Qtum 公链和Qtum联盟链,因为网络环境和参与者的不同,考虑到公链的去中心化程度、参与门槛、安全性和可靠性,量子链开发团队采用IPOS(Incentive Proof of Stake)机制作为区块链网络的共识机制。因为联盟链大多参与者都是受限的节点、身份已知的对手方,对共识机制的考量不同于公链网络,在联盟链中,量子链将采取Proof of Time 和Raft结合的共识协议,实现高速的区块链共识网络。
Qtum的开源代码地址Elwin未找到,支持EVM的虚拟机(EVM/EVM2.0),支持智能合约,适合公链和联盟链。
八、Chain
Chain是由一家刚成立两年的美国创业公司Chain推出,是一个企业级的区块链平台架构,可以让机构构造从零开始更好的金融服务。
作为区块链供应商,Chain在过去的两年多时间中获得了极好的信用。Chain通过将专属区块链和分布式总账的源代码进行开放,可以让更多的人在其软件上增加应用或是建立专属网络。Chain核心开发者版本的创建花费了数年时间,它是区块链供应商和金融机构合作的直接产物。由于这个开源软件针对的是金融领域,因此它允许用户创建和发行他们自己认为合适的数字资产。
Chain 开放标准在以下方面实现突破:
l 全新的共识模型在不到一秒的时间里实现交易的最终完成,即便是交易量非常大也能支持
l 私密解决方案对区块链数据进行加密,并让相关对手方和监管者进行有选择的读取
l 智能合约框架和虚拟机支持简单的规则执行,以及进行键值存储的图灵完整程序
l 可伸缩的数据模型可以为网络参与者降低运行负荷
l 丰富的元数据层可支持满足KYC(了解你的客户)和 AML(反洗钱)要求
开源代码地址为https://github.com/chain/chain,系统主要开发语言是GO,共识协议采用联邦拜占庭协议,支持多种数字资产,适合联盟链。
区块链 | 评论:0
| Trackbacks:0
| 阅读:567
Submitted by admin on 2017, January 9, 10:24 PM
共识(Consensus)过程是一个非常有趣的过程。
在我们的日常生活中,几乎所有的事情都是达成共识的过程。
达成共识越分散的过程,其效率就越低,但满意度越高,因此也越稳定;相反,达成共识越集中的过程,效率越高,也越容易出现独裁和腐败现象。
- 达成共识常用的一种方法就是通过物质上的激励以对某个事件达成共识;但是这种共识存在的问题就是容易被外界其它更大的物质激励所破坏。
- 还有一种就是群体中的个体按照符合自身利益或整个群体利益的方向来对某个事件自发地达成共识;当然形成这种自发式的以维护群体利益为核心的共识过程还是需要时间和环境因素的,但是一旦达成这样的共识趋势,其共识结果也越稳定,越不容易被破坏。
在比特币和其它区块链币中,也存在如何达成共识的问题。或者说,比特币或其它区块链币最核心的问题也是如何在去中心化的环境中达成共识。
区块链是比特币背后的核心技术,也是支撑比特币的基础架构。因此在谈区块链共识,就必然要谈比特币的共识。
比特币最核心的突破是在去中心化的情况下对交易事件达成了共识,即在没有中心组织的情况下对某个交易的有效性达成了一致。
比特币实现这个共识的方法主要包括两个部分:
- 激励;即通过每个区块产生一定量的新比特币来激励参与者;
- 引入外部资源确保安全;即通过大量的外部计算来确保共识的安全性,也就是工作量证明(Proof of Power);
这也是几乎所有PoW币种所采用的的方法。
而这套方法要能持续长期运行下去的前提就是:
- 这种激励对参与者要有足够的吸引力;也就是说比特币要一直涨价,才能吸引参与者持续参与挖矿计算,以维护整个网络的运行;否则就会导致参与的人减少,破坏网络安全;
- 没有外部攻击;由于比特币引入了外部计算来确保安全,因此只要有足够的挖矿算力(超过维护系统算力的51%)就能对系统成功进行攻击,这也是比特币长期存在的安全隐患之一;因为只要有钱,就能买到设备和算力。
正是由于比特币存在的问题,例如消耗大量的资源、外部51%攻击等,出现了PoS(Proof of Stake)共识机理。
总体上,PoS共识理论和实践目前仍处在探索阶段。
最原始的PoS机理就是用股权代替PoW中的挖矿算力,来模拟比特币的挖矿过程。请注意,这个过程没有引入外部资源,而是仅仅依靠自身的币种股份来维护网络安全,因此其不需要消耗大量能源来进行计算;而且由于其没有引入外部的资源,因此不会担心外部攻击,例如外界的算力攻击。
看起来PoS是很完美的,但是它存在一个严重漏洞。
PoS存在内部的Nothing-at-Stake攻击。
什么是Nothing-at-Stake(常写作N@S)攻击?
假设系统中出现了两个分支链,那么对于持有币的”挖矿者“来讲,最佳的操作策略就是同时在两个分支上进行“挖矿”,这样,无论哪个分支胜出,对币种持有者来讲,都会获得本属于他的利益,即不会有利益损失。而且由于不需要算力消耗,因此PoS中在两个分支上挖矿是可行的。
这导致的问题是,只要系统存在分叉,“矿工们”都会同时在这几个分支上挖矿;因此在某个情况下,发起攻击的分叉链是极有可能成功的,因为所有人也都在这个分叉链上达成了共识;而且甚至不用持有51%的币量,就可以成功发起分叉攻击;
而这在PoW中是不可行的,因为挖矿需要消耗算力,矿工只能在一个分支上进行挖矿。
第二个问题是重写历史攻击;即攻击者可以通过购买原始持有币种的账户来从头发起攻击,重新分叉一个区块链。因为原始的币种持有者可以将币转移至其它账户,因此他是可以在没有损失的情况下将原始账户出售给攻击者的。攻击者需要的就是有足够数量币的原始账户;当然了,这也只是概率问题,因为有可能原始账户持有者不会出售他们的账户,但是理论上确实存在这种攻击。
第三个问题是,尽管PoS中的挖矿不用消耗算力,运行成本很低,但是也存在如何激励矿工的问题。因为一般的PoS系统是没有新币产生的,矿工只能赚取交易费,而且在交易费不高的情况下,对矿工的激励也是很有限的。
当然了,也有很多PoS币种解决这个问题的办法就是持续的再产生新币来激励挖矿者,这导致的问题就是通胀。
上述3个问题是PoS要解决的,尤其是N@S的问题尤为重要,因为如果没有其它约束机制,这种攻击是完全有可能实现的。
从以上可以看出,无论是PoW还是PoS机理的共识过程,其必要条件有两个:
- 信息公开共享;
- 个体参与;
以现实为例,事件的信息越透明、所涉及到的人员参与度越高,最终形成的共识也就越稳定、越持久。这与区块链共识是一致的。
【参考阅读】
区块链 | 评论:0
| Trackbacks:0
| 阅读:530
Submitted by admin on 2016, December 28, 12:17 PM
什么是智能合约
智能合约是代码和数据的集合,寄存与Blockchain的具体的地址。智能合约更想是在Blockchain中的一个自动化的代理(或者说是机器人or NPC),智能合约有自己的账户,在时间或事件的驱动下能自动执行一些功能,如可以在相互之间传递信息,修改区块链的状态(账户信息等),以及图灵完备计算(可以用图灵机做到的所有事情,通俗来说就是一般编程语言可以做的所有事情)。以太坊的智能合约是以太坊特定的字节码,被叫做EVM字节码。
智能合约高级语言
用户不可能直接编写EVM字节码,所以以太坊提供了几种编写智能合约的高级语言。
Solidity:类JavaScript,这是以太坊推荐的旗舰语言,也是最流行的智能合约语言。具体用法参加Solidity文档。
Serpent:类Python
LLL:类Lisp
可以根据不同的习惯选择不同的高级语言。这里选用最流行的Solidity
相关概念
以下的概念是智能合约可能用到的,这里不做详细介绍,想了解的可以参考 智能合约菜鸟教程
公钥加密系统:
点对点网络:
区块链:区块链可以看做是智能合约的基础设施
以太坊虚拟机:解释执行智能合约字节码的东西,功能类似于Java虚拟机
节点:
矿工:区块链中参与处理区块的节点叫做矿工。当前以太坊活跃的矿工:https://ethstats.net/
工作量证明:矿工们总是在竞争解决一些数学问题。第一个解出答案的(算出下一个区块)将获得以太币作为奖励。然后所有节点都更新自己的区块链。所有想要算出下一个区块的矿工都有与其他节点保持同步,并且维护同一个区块链的动力,因此整个网络总是能达成共识。
以太币:ETH,以太坊中的虚拟货币,可以购买和使用,也可以与真实货币交易。以太币的走势图
Gas:相当于手续费。在以太坊执行程序以保存数据都要消耗一定量的以太币。这个机制可以控制区块链中计算的数量,保证效率。
智能合约与DApp
以太坊社区把基于智能合约的应用称为去中心化的应用程序(Decentralized App)。DApp的目标是(或者应该是)让你的智能合约有一个友好的界面,外加一些额外的东西,例如IPFS(可以存储和读取数据的去中心化网络,不是出自以太坊团队但有类似的精神)。DApp可以跑在一台能与以太坊节点交互的中心化服务器上,也可以跑在任意一个以太坊平等节点上。(花一分钟思考一下:与一般的网站不同,DApp不能跑在普通的服务器上。他们需要提交交易到区块链并且从区块链而不是中心化数据库读取重要数据。相对于典型的用户登录系统,用户有可能被表示成一个钱包地址而其它用户数据保存在本地。许多事情都会与目前的web应用有不同架构。)
DApp流程:
- 用Solidity(或其他语言)编写智能合约(后缀为.sol)
- 用solc编译器将.sol合约编译成EVM字节码
- 编译好的字节码回送给dapp前端
- 前端将编译好的智能合约部署到区块链中
- 区块链返回智能合约地址+ABI(合约接口的二进制表示。合约接口用JSON表示,包括变量,事件和可以调用的方法)
- 前端通过Address+ABI+nonce,调用智能合约。智能合约开始处理。
智能合约编译器
Solidity智能合约可以通过多种方式进行编译
在这里选择solc和web3.eth.compile.solidity方式
geth安装
参考:go Ethereum client。安装不比较简单,这里详细说了
solc安装
1. 作为cpp-ethereum的一部分安装
如果通过编译的方式安装了cpp-ethereum(参考:http://www.cnblogs.com/fengzhiwu/p/5547911.html),那么solc编译器就会作为cpp-ethereum的一个子项目也被编译安装,在webthree-umbrella/build/solidity/solc目录下找到solc编译器的可执行文件。

然后,在/bin或/usr/bin目录下创建软链接就行了
ln -s /home/vagrant/Code/workspace/webthree-umbrella/build/solidity/solc/solc /bin/solc
2. 单独安装solc
参考:http://solidity.readthedocs.io/en/latest/installing-solidity.html
- 通过npm安装:这种比较简单,运行npm install solc就行了,不过我没有在console中找到solc
- 通过apt-get安装:
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install solc
which solc
把solc添加入geth中直接使用(在geth中输入)
admin.setSolc("path/to/solc")
这种方法和安装cpp-etheruemle类似,不过最后的编译步骤改为:
cd webthree-umbrella
./webthree-helpers/scripts/ethupdate.sh --no-push --simple-pull --project solidity # update Solidity repo ./webthree-helpers/scripts/ethbuild.sh --no-git --project solidity --cores 4 -DEVMJIT=0 -DETHASHCL=0 # build Solidity only
测试
打开一个geth console,输入:web3.eth.getCompilers(),就会打印

智能合约体验
编译一个简单的合约
直接在console中编译一个简单的合约代码
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"
> clientContract = eth.compile.solidity(source).test
编译返回的结果的JSON格式如下

其中,
code:编译后的EVM字节码
info:编译器返回的metadata
abiDefination:Application Binary Interface定义。具体接口规则参见这里
compilerVersion:编译此代码的solidity编译器版本
developerDoc:针对开发者的Natural Specification Format,类似于Doxygen。具体规则参见这里
language:合约语言
languageVersion:合约语言版本
source:源代码
userDoc:针对用户的Ethereum的Natural Specification Format,类似于Doxygen。
编译器返回的JSON结构反映了合约部署的两种不同的路径。info信息真实的存在于区中心化的云中,作为metadata信息来公开验证Blockchain中合约代码的实现。而code信息通过创建交易的方式部署到区块链中。
创建和部署合约
在进行此步骤前,确保你有一个解锁的账户并且账户中有余额。(可以创建自己独立的测试网络,即自己的区块链,初始化的时候就可以初始化一些有余额的账户)。参考:Test Networks

现在就可以在区块链中创建一个合约了。创建合约的方式是发送一个交易,交易的目的地址是空地址,数据是前面JSON结构中的code字段。
创建合约的流程如下
var primaryAddress = eth.accounts[0] var abi = [{ constant: false, inputs: [{ name: 'a', type: 'uint256' } ]}] var MyContract = eth.contract(abi) var contract = MyContract.new(arg1, arg2, ..., {from: primaryAddress, data: evmByteCodeFromPreviousSection}) //arg1,arg2,...是构造参数,这里没有,需要去掉。红色部分用前面生成的code代替
i. 获得账户

ii. 定义一个abi (abi是个js的数组,否则不成功)

iii. 创建智能合约

iv. 发送交易部署合约

如果交易被pending,如图说明你的miner没有在挖矿,

启动一个矿工
miner.setEtherbase(eth.primaryAddress) //设定开采账户
miner.start(8)
eth.getBlock("pending", true).transactions
这时候发现交易已经在区块中

不过会发现,交易还是pending,这是因为该交易区块没有人协助进行运算验证,这时候只需要再启动一个矿工就行了
miner.start(8)
参考:Private Testnet
发现区块1部署了交易


与合约进行交互
可以通过eth.contract()定义一个合约对象,这个对象包含变数合约接口的abi
Multiply7 = eth.contract(clientContract.info.abiDefinition); var myMultiply7 = Multiply7.at(contract.address);


到这儿,就可以调用智能合约的函数了。
myMultiply7.multiply.call(3)
或
myMultiply7.multiply.sendTransaction(3, {from: contract.address})

结束
到此,对智能合约的初次体验就结束了。另外智能合约以及DApp还可以干很多NB的事情。以后会进一步讨论。
以太坊 | 评论:0
| Trackbacks:0
| 阅读:672
Submitted by admin on 2016, December 22, 6:08 PM
一般而言,在介绍区块链时经常会提到两个例子:一是由古老的记账模式延伸到分布式账本,二是拜占庭将军问题(Byzantine Generals Problem)。使用分布式账本目的是让每个节点都能够验证交易,而拜占庭将军问题与账本的一致性有关,即本文要讨论的共识机制(Consensus)。
区块链上的共识机制主要解决由谁来构造区块,以及如何维护区块链统一的问题,该问题的理论基础是拜占庭容错(Byzantine Fault-Tolerant,BFT)。BFT从上世纪80年代开始被研究,目前已经是一个被研究得比较透彻的理论,存在解的前提条件及具体实现都已有现成算法。不过本文不打算从BFT说起,因为要分析的是区块链共识机制的演进过程,而中本聪并没有采用BFT。其实在我研究比特币伊始,即便在理解了POW机制之后的很长一段时间内,并不了解拜占庭将军问题。后文分析 HyperLedger Fabric的PBFT以及小蚁项目的DBFT时再全面阐述拜占庭将军问题及传统分布式一致性算法(PAXOS、RAFT)。
共识机制的核心是区块的构建和检验,POW系统构建区块的过程一般称为“挖矿”(mine),POS 系统PPC的区块构建方式一般称为“铸造”(mint),而NXT的区块构建方式一般称为“锻造”(forge)。
POW
共识机制在以前一般被称为证明方式(Proof),因为比特币采用工作量证明(即Proof-Of-Work,简写为POW)。随着大家对分布式账本一致性问题的不断探索,很多方法被提出来,尤其近期有很多区块链项目回归了对传统BFT算法的改进,在思路上已经跳出了“证明”的语义,因此进一步高度概括为共识机制。我记得第一次碰到工作量证明这一概念时感到很费解,对这种表述方式很头疼,掌握了POW机理后才真正明白,通俗讲就是“通过工作以获得指定成果,用成果来证明曾经付出的努力”。其实我们日常工作生活中经常使用工作量证明,比如学生考试成绩,毕业证以及驾照等,这种证明方式的一个显著特征是往往需要很大的工作量才能拿到指定成果,但这个成果很容易验证。因为我们一般很难去实时监督一个人是否真的付出了这些工作量,所以只能使用工作量的结果来证明。
再回到比特币的设计思路,中本聪已经使用非对称密码解决了电子货币的所有权问题,用区块时间戳解决了交易的存在性问题,用分布式账本解决了剔除第三方结构后交易的验证问题,剩下需要解决的问题是双重支付,这要求所有节点账本统一,而真正的平等又必须赋予人人都有记账的权利,记账是一件简单的事情,每个人都可以做,显然最终会存在众多大同小异的账本,但我们只需要其中的一个账本就够了。
中本聪想到给记账加入成本,总账本由各个分页按照时间先后排序,给每个账本分页设立一个评判标准,以区分账本分页是否合格,这给记账增加了难度,同时给每个账本分页加入一个随机元素,用以调节记账难度以保证一定时间段内只有一个人生成合格的账本分页。增加的成本就是工作量,合格的账本分页就是工作量证明。对于比特币而言,所谓的账本分页就是一个区块,区块通过巧妙设计形成区块链,合格的区块可以表述为:
F(Nonce) < Target
其中Nonce是随机元素,Target是合格区块的量化,每个记账节点的Target一致。此外POW的成功运行还需要配合如下两条约定,
Best chain原则:将最长的链条视为正确的链条。
激励原则:找到合格的区块有奖励收益。
第1条约定为硬性规则,无条件遵守,大家要么不玩,要玩就遵守这条原则,毕竟共同的目标是找到一致性账本,而最长的链条代表最大的工作量,如果没有这条约定,每个人都只会构造自己的区块链,无法统一。第2条为工作量激励,既然记账有成本,那唯有收益才能驱动大家都去记账,参与记账构造区块变成投资行为,其成本和收益风险在第1条约束下形成博弈,驱动所有节点按约定规则老老实实够造区块,最终达到纳什均衡。
具体实现方式,比特币采用哈希(Hash)算法,关于哈希算法的原理和特点在前一篇文章(挖矿演进)已经详细讨论。逻辑上比特币是对整个区块进行哈希运算,但真正实现并非将整个区块数据作为哈希函数的参数,区块大体可分为区块链头和交易列表两部分,交易列表通过构造成Merkle树最终浓缩成Merkleroot内置于区块头,区块头只有6个字段,共80字节,如此设计首先带来的好处是方便哈希运算,每次运算只需要80字节的参数输入,而不是整个区块的数据,但交易列表的任何变化又能体现在哈希运行结果上。

比特币采用SHA256哈希运算,且每次都是连续进行两次SHA256运算才能作为最终结果,前一次运算的结果作为后一次运算的输入,即Double SHA256,一般简称SHA256D,扩展上面的公式,比特币合格区块判断依据如下:
SHA256D(nVersion,hashPreBlock,hashMerkleRoot,nTimes,nBits,Nonce)<MAXTARGET/Diff
其中式子左边的6个参数(区块头)在前一篇文章已经解释,MAXTARGET为最大目标值,常量;Diff代表难度,全网难度一致。MAXTARGET/Diff即通常所说的当前目标值。
很显然,POW的核心要义为:算力越大,挖到块的概率越大,维护区块链安全的权重越大。相对其他共识机制而言,POW逻辑简单,容易实现,容错达50%,其安全有严格的数学论证。
POS
POW并非完美,其中被指责最多的主要有两点,一是浪费能源,二是风险和收益博弈必然导致联合挖矿,而大算力矿池可能会对系统的去中心化构成威胁。
于是在2011年,一个名为Quantum Mechanic的数字货币爱好者在Bitcointalk论坛提出Proof-of-Stake(POS)证明机制,该机制被充分讨论之后证明具有可行性。如果说POW主要比拼算力,算力越大,挖到一个块的概率越大,POS则是比拼余额,通俗说就是自己的手里的币越多,挖到一个块的概率越大。POS合格区块可以表述为:
F(Timestamp) < Target * Balance
与POW相比,式子左边的搜索空间由Nonce变为Timestamp,Nonce值域是无限的,而Timestamp极其有限,一个合格区块的区块时间必须在前一个区块时间的规定范围之内,时间太早或者太超前的区块都不会被其他节点接纳。式子右边的目标值引入一个乘积因子余额,可见余额越大,整体目标值(Target * Balance)越大,越容易找到一个区块。因为Timestamp有限,POS铸造区块成功率主要与Balance有关。
POS只是代表一种共识机制理念,具体有多种实现方式,下面重点解析两种比较经典的实现思路。
Peercoin
Peercoin(点点币,PPC)于2012年8月发布,最大创新是其采矿方式混合了POW工作量证明及POS权益证明方式,其中POW主要用于发行货币,未来预计随着挖矿难度上升,产量降低,系统安全主要由POS维护。目前区块链中存在两种类型的区块,POW区块和POS区块。PPC的作者为同样不愿意公开身份的密码货币极客Sunny King,同时也是Primecoin的发明者。
要掌握Peercoin的POS机制,需要重点理解Sunny King专门为PPC设计的几个核心概念:Coinstake,Kernel,Stake Modifier,Modifier Interval,Stake Reward,Coinage等。
Coinstake
为了实现POS,Sunny King专门设计了一种特殊的交易,叫Coinstake,Coinstake的设计借鉴于中本聪的Coinbase设计。本质上Coinbase和Coinsake都是一笔交易,只是对他们的输入输出做了一些硬性限制。
而Coinstake的设计又需要有别于Coinbase,这样才不会扰乱系统原有的POW机制,简单对比一下两者结构上的不同,
Coinbase结构要求:
输入数量必须等于1,且输入的prevout字段(指定前一笔交易的输出)必须置空值。
输出数量必须大于等于1。

Coinstake结构要求:
输入数量大于等于1,且第一个输入的prevout字段不能为空,即要求Kernel必须存在。
输出数量大于等于2,且第一个输出必须置空值。
这两种特殊交易在区块链中存放的位置也有特殊要求,中本聪规定每个区块的第一笔交易必须放置Coinbase,反之,Coinbase不能出现在区块的其他位置。Sunny King显然不想破坏这个规则,他增加了一条规则,对于POS区块,第二笔交易必须放置Coinstake,反之,Coinstake不能出现在其他地方。换言之,只要第二笔交易是Coinstake,那么这个区块就当POS区块来处理。
Coinbase和Coinstake都不会被单独广播,而只存在于区块中,因此客户端节点一般都不允许进入内存池,当花费这两种交易时,都需要检测是否已经成熟。
Kernel Protocal
Coinstake的第一个输入(Input 0)叫Kernel,Kernel在POS机制里确实起到核心作用,合格区块的判定与之息息相关。PPC合格区块判断条件为:
SHA256D(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime)< bnTarget * nCoinDayWeight
式子左边的每一个参数都有明确的设计目的,其中,
nStakeModifier
:专门为POS设计的调节器,按照以上公式,如果没有参数nStakeModifier,当一个人收到一笔币得到网络确认之后,他立即就能提前计算得知自己在未来何时可以锻造区块,这显然不符合设计目标,Sunny King希望POS矿工和POW矿工一样做盲目探索,以实时在线维护区块链,nStakeModifier的设计就是为了防止POS矿工提前计算。nStakeModifier可以理解为POS区块的一个属性,每一个区块对应一个nStakeModifier值,但nStakeModifier并不是每个区块都变动,不过协议规定每隔一定时间(Modifier Interval)必须重新计算一次,取值与前一个nStakeModifier以及最新区块哈希值有关,因此POS矿工无法提前计算,因为他不知道未来的区块哈希值。
也就是说,在PPC系统中,除了存在区块链,币链(币的交易签名历史),还隐藏着一个很少被提及的链条——权益调节器链条。
值得一提的是,Sunny King是在PPC后来的版本才加入这个调节器的,一开始他使用nBits。
txPrev
:Kernel对应的前一笔交易。
txPrev.block.nTime
:txPrev所在区块的时间戳,一笔交易被纳入区块的时间是交易发起者不能确定的,节点有可能通过提前计算预估到未来对自己有利的时间戳,这个参数就是为了防止节点利用这种预估优势提前生成大批交易。
txPrev.offset
:txPrev在区块中的偏移量,用以降低网路节点同时生成coinstake的概率。
txPrev.nTime
:txPrev构造时间,设计目标如txPrev.offset。
txPrev.vout.n
:Kernel在txPrev中的输出下标,设计目标如txPrev.offset。
再看等式右边,
bnTarget
:全网当前目标难度基准值,类似POW中的当前难度值,由nbits记录。
nCoinDayWeight
:Kernel的币龄。
由以上式子可知,Sunny King一方面希望能给POS矿工提供充足的随机性,另一方面搜索空间严格局限于Coinstake的时间戳字段,以保证影响找到合格区块链的最大因素是Kernel的币龄。
节点在锻造区块时,首先从自己所有的UTXO中选定一个作为Kernel,构造coinstake,计算hash,如果不合格,重新构造coinstake,重构时时间戳Time会改变,也可以改变Kernel,以得到不同的Coinstake,如此往复,直到找到合格区块。
Coinage
上面提到了币龄,也叫币天,假如1.5个币存在于区块链中10天,币龄数值为:
Coinage = 1.5*10 = 15
PPC采用币龄,而不是直接采用余额(Balance)来计算。一个UTXO一旦被花费,其币龄被清零,新的UTXO币龄从0开始算起。
stakeReward
权益激励,俗称获得利息,计算公式如下:
stakeReward = nCoinAge * 33 / (365 * 33 + 8) * 0.01 * COIN
公式可简化为:
stakeReward = (0.01 * nCoinAge / 365) * COIN
其中nCoinAge是Coinstake所有输入的币龄总和,由公式可知收益按1%年率计算。理想状态下,假设所有的币全年都参与挖矿,代币总量每年有1%通胀率,这一设计为很多人所诟病,而且,这一设计并不能激励矿工积极参与挖矿以维护区块链的安全,因为如果不考虑手续费,持币用户每隔几个月打开节点铸币,或者实时在线铸币,理论上收益都是一样的。
stakeMinAge
POS系统也存在51%币龄攻击风险,为了增加攻击难度,Sunny King对每一笔UTXO的铸币资格做了最小年龄(stakeMinAge)限制:一个UTXO在区块链存在的时间小于stakeMinAge则没有铸币资格,PPC最小币龄为8小时。
后来有些竞争币种加入了最大年龄(stakeMaxAge)限制:一个UTXO在区块链存在的时间大于stakeMaxAge则币龄始终按stakeMaxAge计算。
在Sunny King设计的POS机制中,一笔UTXO就像是一个矿工,该矿工每成功铸造一个区块后必须休息一段时间,因此,整套系统必须保证足够多的“矿工”同时在线铸造区块,才有可能获得平滑的出块速度。
Nextcoin
2013年9月,一个名为BCNext的用户在Bitcointalk论坛发起一个帖子,宣布将发行一种全新的纯POS币种,后来取名为Nextcoin,简称NXT。与当时其他山寨币直接Fork自Bitcoin源码的开发思路不同,BCNext另起炉灶,采用JAVA语言从头开发NXT,并对区块结构,交易结构,非对称密码等做了很多改进。NXT有很多创新点,这里只讨论其中最重要的创新——透明锻造(Transparent Forging)。
NXT的POS实现方式与PPC完全不同,合格区块判定方法为:
hit < baseTarget * effectiveBalance * elapseTime
其中,
hit:
NXT抛弃中本聪的UTXO设计方案,采用账户(Account)余额方案,每一个账号对应一个私钥。每一个区块都有一个生成签名(generationSignature)字段,hit的生成与这个字段有关。当用户需要锻造区块时,首先计算自己独一无二的hit,计算过程如下:
用户用自己的私钥对上一个区块的generationSignature进行签名,获得自己本区块的generationSignature。
对上一步结果进行SHA256运算,得hashdata。
取hashdata的前8个字节(共64比特位)作为hit变量。
生成签名的设计有点类似于PPC的stakeModifier,也就是说,NXT区块链下隐藏着一个签名链条。
式子右边,
baseTarget
:全网难度基准值,这个难度按照每分钟一个区块目标调节。
effectiveBalance
:账户有效余额,一笔币转到账户需要足够多的确认才有铸币权利,叫有效余额。
elapseTime
:当前时间与上一个区块时间间隔,按照currentTime-lastBlockTime计算。
分析以上式子,如果依然将式子左边视为挖矿,右边视为目标值,可知用户压根就没有搜索空间,因为当全网产生一个最新区块时,对于锻造下一个区块,每个用户自身的hit就固定了。式子右边,每个用户的目标值与自身的账户有效余额成正比关系,而且,随着时间往前推移,目标值不断变大,不等式最终一定会成立,即理论上每个节点都可以挖那个区块,但规定优先选择最早生成的区块。

用上图类比NXT的锻造机制,每个圆柱体自身高度(hit)是固定的,假设限高杆不断升高(目标值target随着时间不断增大),最终所有圆柱体都能通过(合格区块),但高度最矮的圆柱体可以率先通过。
节点段造区块流程为:账户必须实时在线,当全网有最新区块产生时,每个账户立即计算自己对应的hit,然后根据公式elapseTime = hit/(baseTaret * effectiveBalance)计算得知自己锻造区块的期望时间值,并将这个期望时间广播给网络其他节点,如此,全网每个节点都知道其他节点的期望时间,从而也就得知下一个区块优先由谁来锻造。账户在自己的时间窗口锻造好区块并立即广播全网,其他节点检验一个新区块是否有效,首先要检验证区块的生成签名是否有效,还要检验新区块的时间戳是否与产生区块的节点之前发布的期望时间吻合。每次客户端检测到网络中有新的区块产生,都会重新计算自己的期望时间并向全网发布。
因为hit是用户用自己的私钥签名的结果,因此对于不同用户来说具有很大随机性,即便余额很少的用户,如果运气足够好,hit值很小,也有可能快速锻造区块。
NXT区块的生成完全摒弃了竞争的理念,有点“上帝早已安排好一切”的味道,下一个区块由谁来生成冥冥中早就注定了,全网节点能做的就是静静等待那一刻的到来。

如图,如果节点A没有在自己的锻造时间窗口内广播区块怎么办,没问题,网络会等B的区块,但是如果A和B间隔不远,或者由于网络传输原因部分节点先收到A的区块,部分节点先收到B的区块呢,网络就分叉了,此时Bestchain的原则依然是首选最长的链条,长度一致的分支,优先选择最高区块时间戳最小的分支。那如果节点对所有分支都锻造并广播区块呢,那就变成了一种攻击行为,网络最新区块附近的分叉会加剧。缓解问题的办法是让节点只挖最优分支,这一点没法体现在协议中,只能依靠诚实节点的自律。
摒弃了竞争的理念,NXT共识不得不高度依赖于时间轴,节点虽可预知自己在未来何时可生成区块,但必须要等到那个时候才能广播区块,如果节点提前广播,网络其他节点将不会接受,BCNext在客户端实现上做了限制:对于最新区块,客户端只接受本机当前时间前后15秒范围内广播的区块,这种限制也没法体现在协议上,只能依靠客户端实时辅助实现。
也难怪,NXT代币全部预挖,如果采用类似比特币那样由矿工慢慢发行模式,免不了竞争段造区块,而一旦竞争,区块链将立即陷入分叉。NXT整套共识规则的成功运行其实背后有一个潜在的利益博弈,即,持币者就是系统使用者,也是系统的受益者,大家应该联合起来共同维护区块链,做一个诚实的节点。
也许你会想到一种攻击方法:即便手里持币量很少,但可通过生成大批账号并往每个账号转少量币,以每次都能找到很小的hit,也能快速锻造区块,如此一来POS就退化到类似POW的尴尬境地。BCNext首先从非对称签名算法下手,采用ED25519代替比特币的ECDSA,前者的计算难度比后者大。此外成熟期提高到1440个区块(1天),即一个账号有效余额一旦成功锻造一个区块,该部分余额需要等1天才能重新获得锻造资格。
短暂的分叉还是不可避免的,NXT最新区块附近会有很多分支,一笔交易需要多一些确认才足够安全,NXT官方推荐10个确认。
POS2.0
PPC的成功运行很快就吸引了一批追随者,其中较为出名的包括新星币(Novacoin,NVC)、黑币(blackcoin,BLK)等。黑币社区认为币龄可能会被恶意的节点滥用以获得更高的网络权重并成功实施双花攻击,于是发布POS2.0白皮书,对PPC做了几个细节优化,解决了一些潜在的安全问题,其中最重要的改进是用余额代替币龄,合格区块的条件由:
F(Timastamp) < Target * 币数 * 币的年龄
变为:
F(Timastamp) < Target * 币数
如此一来,一笔UTXO无论放置多久其锻造区块的能力不变,此举可激励节点必须更多的保持在线进行铸币,提高系统安全性,将攻击途径减少到最低限度,并且能够显著提高网络保持运行的节点数量。
POS3.0
黑币社区后来进一步升级,推出POS3.0版本,对交易手续费,难度调整做了一些优化,其中最显著的改变是将1%年利率奖励机制变为固定数额奖励(每个区块固定奖励1.5BLK),此举不但降低代币通胀率(考虑到会有代币永久丢失,低额奖励机制回归总量恒定的设计思路),同时意味着持币节点必须实时在线才能获得收益。
DPOS
比特股(Bitshares)项目于2013年8月开始启动,这是一个野心勃勃的项目,对区块链做了很多改造,并引入许多新概念和特征,尤其令人眼花缭乱的 Bitshares X、多态数字资产交易平台、资产锚定等新名词,一时令人无比兴奋而又困惑。此时POW和POS都已成功运行许久,彼此优劣已被反复讨论,两大阵营时至今日依然争论不休。按照项目规划,比特股对交易容量和区块速度有极高要求,显然POW或POS都达不到要求,于是比特股发明了一种新的共识机制——Delegated Proof-Of-Stake(DPOS),即股份授权股权证明。
DPOS很容易理解,类似于现代企业董事会制度,比特股系统将代币持有者称为股东,由股东投票选出101名代表,然后由这些代表负责产生区块。那么需要解决的核心问题主要有:代表如何被选出,代表如何自由退出“董事会”,代表之间如何协作产生区块等。
持币者若想成为一名代表,需先拿自己的公钥去区块链注册,获得一个长度为32位的特有身份标识符,用户可以对这个标识符以交易的形式进行投票,得票数前101位被选为代表。
代表们轮流产生区块,收益(交易手续费)平分。如果有代表不老实生产区块,很容易被其他代表和股东发现,他将立即被踢出“董事会”,空缺位置由票数排名102的代表自动填补。
从某种角度来说,DPOS可以理解为多中心系统,兼具去中心化和中心化的优势。
总结
最后从几方面来简单对比分析以上几种共识机制的优劣和特点:
安全性
POW的安全性存在完整的数学证明,这一点是POS和DPOS无可比拟的优势。区块链共识机制一般要同时考虑抵御DDOS攻击和双重支付攻击,POW存在51%算力攻击威胁,比特币目前超强的算力使得破坏该系统需付出巨大代价。POS也会存在51%币龄攻击,而DPOS安全性完全取决于代表的诚实程度。NXT理论可以实现快速交易,但需要锻造节点曝光自己的IP,如此一来容易成为DDOS攻击对象,DPOS的代表也容易成为DDOS攻击对象。
环保性
在不可能三角理论(去中心化,安全,环保不能同时兼备)中,POW彻底抛弃节约能源的需求,通过巨大算力来维护系统安全和去中心化特征。POS和DPOS几乎不费多余电力,但不可避免在另外两个特性做出牺牲。
共识速度
POW很难缩短区块时间,POS相对而言可以缩短区块时间,尤其NXT会比PPC的实现方式更快,DPOS也可以在很短时间内达成共识,比特股目前30秒产生一个区块。不过POS更容易产生分叉,尤其NXT,所以交易需要等更多确认才被认为安全。
交易容量
这是区块链未来发展需要解决的核心问题,巨大的交易容易意味着巨大的带宽和存储空间,POW的交易容量很难扩展,而NXT由于每个节点都可以预知下一个区块由谁锻造,可以直接将交易发给锻造节点,因此NXT交易容量有很大扩展性。从某种角度来说,DPOS可以理解为多中心系统,兼具去中心化和中心化的优点,如果代表节点都运行强大的服务器且彼此带宽足够大,理论上交易处理能力可比拟传统中心化系统,比如Visa。
出块平滑度
POW由于哈希算法特性,可以得到平滑出块速度,而且可以间隔一段时间再调整全网难度,POS出块主要与余额有关,而用户余额差距梯度比较大,所以POS一般每个块都要调整全网基础难度。DPOS依靠有限代表人的协同作用,如果代表人不会频繁进出,几乎可以做到固定死出块间距。
最终性
POW和PPC通过竞争达成共识,不存在最终性,理论上如果有足够算力,现在可以从头挖比特币区块链,不过可以依靠检测点实现最终性。NXT和DPOS严格依赖时间轴,依靠节点实时在线检测,所以存在最终性。
综合各方优势,个人认为POW适合应用于公链,如果搭建私链,因为不存在验证节点的信任问题,可以采用POS比较合适,而联盟链由于存在不可信局部节点,采用DPOS比较合适。
区块链 | 评论:0
| Trackbacks:0
| 阅读:674