分类目录归档:随笔

矿工指引:如何安全的硬分叉到Bitcoin Unlimited

由于 Bitcoin Unlimited 并没有程序来控制硬分叉启动的条件,所以硬分叉到 Bitcoin Unlimited 需要参与的矿池联合起来,达成一致行动。另外矿池如果配置不当可能会造成遭受大块攻击,或者造成比特币网络突然的提前分叉,这是非常危险的。随着越来越多的矿池对 Bitcoin Unlimited 感兴趣,我建议矿池按照下面所述的步骤来实施硬分叉。

整个硬分叉过程应该分为三步。第一步:算力投票阶段,如果在一个完整的难度周期中,由 Bitcoin Unlimited 挖出的区块占比等于或大于 75% 则进入下一步骤。第二步:锁定阶段,共两个难度周期,供比特币社区升级他们的软件到 Bitcoin Unlimited, 如果两个难度周期内任何一个难度周期中 Bitcoin Unlimited 的区块没有满足 75% 条件,则回到第一步。第三步:实施阶段,开始硬分叉。

在第一步中,如果矿池配置不当或者使用 Bitcoin Unlimited 的默认配置,可能会遭受到别有用心的人发出的大区块攻击。如果这时候 Bitcoin Unlimited 算力占比比较小,会造成 Bitcoin Unlimited 一方工作在错误的链上,造成严重损失。如果双方势均力敌,那么比特币会面临分裂的危险。如果已经到了第二步,那么分叉会发生在预定的时间之前,这会造成混乱。

我的建议是矿池在第一步和第二步的时候,把 Bitcoin Unlimited 配置为 EB1/AD6, 其含义为接受 1MB 大小的区块,如果有更大的区块,只有在该大区块之后有 6 个或以上的区块,并且包含大块的链为最长链,那么比特币节点会切换到包含大区块的链上。可以通过在 Bitcoin 配置文件中添加下面两行来实现:

excessiveblocksize=1000000
excessiveacceptdepth=6

在这样的设置下,攻击者必须要有 51% 以上的算力才可以实现大区块攻击,已经足以保证安全了。AD 不宜设置的过大,因为在到达到第三步的时候,矿池不大可能在同一时间切换,AD6 的设定保证矿池即使没有及时修改配置,也可以及时切换到最长链,降低损失。

另外,矿池还需要设置区块版本号和挖出的区块大小。Bitcoin Unlimited 的默认版本号为 Bitcoin Classic 的版本号 0x30000000,这是容易引起误解的,建议改为 0x20000000. 另外,挖出的区块大小应配置为 1MB. 可以通过在 Bitcoin 配置文件中添加下面两行来实现:

blockversion=536870912
blockmaxsize=1000000

到达第三步之后,矿池修改接受的区块大小和挖出的区块大小,开始硬分叉。我建议先硬分叉到 2MB,这是经过充分测试证明网络能够支持的大小,是风险最低的选择。可以通过修改 Bitcoin 配置文件来实现:

excessiveblocksize=2000000
blockmaxsize=2000000

相信通过这样的步骤和配置,可以让硬分叉变得更安全。

为什么比特币需要区块扩容以及为什么选择Unlimited

在2016年10月10日,也就是比特币在米兰的第三次扩容会议刚刚结束之后,我选择了把 ViaBTC 矿池的 Bitcoin 版本从 Bitcoin Core 切换到了 Bitcoin Unlimited. 当然,这一决定是在争取到绝大部分矿池用户的同意之后做出的,我不能把我的意志强加到用户身上。比特币区块扩容与否,是由所有比特币矿工所决定的。但是在扩容这件事情上,矿池的管理员相比于矿工有更多的专业能力,能够做出更好的选择。并且从以往的经验来看,矿工参与投票的积极性非常低。所以,我认为矿池管理员应该负起责任,做出自己的选择。

ViaBTC 在 Coinbase 中投票支持 2MB 区块大小,目前仍然挖 1MB 大小的区块,以保证与比特币主链的兼容。不需要为这个大小担心,因为这只是一个开始,一旦硬分叉成功实施,再升级区块大小就很容易了。我还特意的设置了区块版本号,没有使用 Bitcoin Unlimited 默认的 BIP109 区块版本号,因为 Bitcoin Unlimited 并没有实现 Bitcoin Classic 的 BIP109,我们也不想实现 BIP109. 也希望 Bitcoin Unlimited 开发者后续能够去掉这个默认的版本号,防止引起误解。

在我们发现第一个 Bitcoin Unlimited 区块之后,比特币社区引起了很大的反应,有很多争议和猜测,所以我觉得有必要说些什么,来澄清一些事实,阐述我的看法。

为什么比特币需要区块扩容?

很简单,如果比特币区块不扩容,那么比特币将走向失败。这不是说加密电子货币会失败,也许会有新的币替代比特币的地位。比特币还远远处于它的发展的早期,越来越多的人开始使用比特币。然而,由于临时性的 1MB 区块大小的限制,比特币开始拒绝新的用户的加入,在我看来,这是一种自杀行为。慢慢的,比特币交易费会变得高的不可接受,人们会转向其它竞争币。用户的流失对比特币的发展是致命的打击,这不是猜测,是正在发生的事情。另一方面,没有足够多的链上交易,比特币矿工获取不到足够多的交易费,若干年后,比特币挖矿变得无利可图,这会让比特币系统安全性大大降低。无论如何,这都会导致比特币的失败。

为什么隔离验证是垃圾?

人们说隔离验证能够安全的让比特币扩容到1.7MB,所以应该支持隔离验证,这种想法真是一叶障目。1.7MB的扩容只是减缓了比特币的死亡而已,并没有根本的解决了这个问题。并且就算隔离验证真的激活了,并不代表所有人都会马上使用隔离验证交易,真正达到1.7MB需要1年以上的时间,根本没法解决目前交易拥堵问题。另外,隔离验证给比特币社区带来了巨大的技术债务,大幅修改了比特币交易格式,需要所有的比特币节点、矿池、区块浏览器、钱包、交易所等比特币应用进行升级。这样的代价远远大于硬分叉,而这所有的一切,仅仅是为了1.7MB的扩容?别忘了,Bitcoin Core 提出隔离验证是为了阻止比特币通过硬分叉的方式扩容。一旦隔离验证得到激活,那么Core团队再也不会有硬分叉扩容了。比特币区块大小将会锁定在1MB的大小,不可避免的走向死亡。

为什么闪电网络行扩容行不通?

首先,闪电网络应用场景非常有限。想想人们为什么要使用比特币,是为了更快的交易确认速度还是因为比特币是一种去中心化的货币?比特币牺牲了速度和效率,带来了去中心化的安全,缓慢的确认速度对于比特币来讲并不是问题。其次,闪电网络上的交易并不是真正的比特币交易,和交易所内部的发生在数据库上的交易没有本质的区别。部署闪电网络对于普通用户来讲非常困难。如果闪电网络真的部署成功,成为比特币交易的主要形式,那么最后会形成多个中央节点,用户需要把币寄存在这些中央节点里面,这和现存的银行系统有什么本质的区别?最后,把比特币当做结算网络的想法非常可笑,比特币先是数字货币,然后才是结算网络,一旦比特币失去了货币属性,那结算属性立刻崩溃。闪电网络也不是一无是处,能够解决一部分问题,可以替代一部分比特币交易,但想把闪电网络作为主要的比特币交易通道行不通。

为什么选择Bitcoin Unlimited?

我们在区块大小这个问题上,浪费了太多的时间,我们需要一劳永逸的方案解决区块大小的问题。过大或者或小的区块都不合适,这应该交由市场来选择,随着比特币网络和技术的进步动态的调整。Bitcoin Unlimited 的扩容方案把区块大小的选择交给了矿工,符合我们的需要。Bitcoin Unlimited 允许矿工设置自己挖掘的区块大小和接受的区块大小,并通过 Coinbase 对区块的大小进行投票。如果节点发现有更大区块的链长度大于当前的链4个区块(默认)长度,会自动切换到最长的链而忽视区块的大小,这让比特币再次升级区块大小变得很容易。

为什么硬分叉并不危险?

硬分叉最大的危险在于,有可能出现两条链。但据我所知,在比特币扩容这件事情上,人们没有本质的分歧,绝大数人希望扩容,只是选择的方式不同。以太坊出现两条链是因为人们出现了本质的分歧,那就是:区块链是否可以被修改?并且,由于比特币难度调整的滞后性和10分钟1个区块的设定,在绝大部分算力支持硬分叉的情况下,出现两条链的可能性很小。原链会由于过慢的处快速度变得不可用,理性用户会选择新链,留下的矿工收益会大大降低,理性的选择也是切换到新链。

应该如何实施硬分叉?

对于 Bitcoin Unlimited 来讲,并没有一个程序自动设定的阈值。理论上来讲,只要有矿池愿意,任何时间都可以启动分叉,但这很危险并且意义不大。在 Bitcoin Unlimited 硬分叉这件事情上,矿池需要联合起来,达成一致行动。

首先,什么条件下启动硬分叉?我建议使用 Bitcoin Classic 的 75%的阈值,就是支持 Bitcoin Unlimited 的算力占比达到 75% 以上的时候再启动硬分叉。如果阈值过高,共识几乎永远不可能达成。75%的算力支持足以进行安全的硬分叉。

其次,什么时间启动硬分叉?我建议,首先,留够最少1个月的时间,为比特币社区升级自己的节点做准备。其次,我们应该选择在一次难度调整之后的马上进行分叉,让留在原链的算力调整难度变得异常困难,不得不放弃原链。

写在最后

纵观 Core 以及 BlockStream 在米兰比特币扩容会议上的种种提案,都是以杀死比特币和矿工为己任。在关系到比特币矿工和用户的切身利益时候,我们需要联合起来,让比特币重生。

在止损最小时开仓,在市场疯狂时平仓

这简单的两句话,就构成了一个简易的交易系统。

首先谈谈止损。是否会止损,是衡量一个交易员是否入门的标准。交易最大的错误,就是开仓的时候不明确设止损。没有止损保护的仓位,会让自己的交易账户失控,变得和赌博无异。但是,胡乱的设置止损对账户的伤害也很大。比如根据盈亏额度或者比例来止损,往往导致止损在震荡的高点或者低点。或者在大行情到来之前,确因为一个小回撤就止损出局。设置了止损,不严格执行也是白搭。严格执行止损不仅包括止损条件到了就平仓,还有要严格执行交易计划,不随便更改止损位置。想必有经验的交易者对这几句话都有感触。

什么是成功的止损?简单的来说,成功的止损就是在止损后,市场趋势反转,或者给你带来一个更好的进场位置。那么,最好的止损位置,就是最容易明确判断市场走向的位置。如何判断市场的转折点,就要靠技术分析了。技术分析通过趋势线,压力线,形态或者指标来判断市场的转折,往往是很明确的。价值投资因为信息不透明或者很难衡量信息的分量,所以很难确定止损位置,这是价值投资的劣势。

那么很显然,止损最小的时候就是最好的进场时候,这里说的止损当然是成功的止损,瞎止损不算。较小的止损我们能够通过较小的风险来博取较大的收益。我们需要做的就是寻找最小止损的时候交易。什么时候止损最小,就是技术分析的范畴了,我这里说几个把握比较大的方法:

缩量横盘很久后向一个方向突破。横盘时因为市场多空力量处于势均力敌之中,向一个方向突破是因为有新的力量打破了这一僵局。所谓横有多长,竖有多高。在价格突破近期的高点或低点开仓,止损很简单,市场突破后又回到原来的震荡区间,说明是假突破。这种例子在市场中非常常见。

三角整理区突破。三角整理区一般发生在趋势的进行的中间,也可以构成市场的反转,突破后往往意味着趋势的继续或反转。这时候往往是一个比较好的入场时机。在突破时开仓,止损很简单,没有有效突破止损。

压力/支撑线突破。压力线就是把市场连续几个波峰的高点练成的一条线,支撑线就是市场连续几个低点连成的一条线。最明显的例子就是2014年底上证指数突破数年的压力线,后面的事情大家都知道了:

新高新低突破。前期的高点/低点往往会变成重要的压力/支撑位,如果突破该点位形成新低或新高,说明有重要的力量打破该预期,顺着突破的方向开仓。《海龟交易法则》一书中所用的交易系统就是一套新高新低突破交易系统。还以上证指数为例,在今年三月份上证指数突破3400点得时候,就和朋友说,这可是能最好的买点了(但指数并不代表个股,指数突破不代表个股突破,比如金三胖在当时表现并不好,这也是股市的复杂之处):


上面说的这几种方法,所用的周期越长越有效,最少应该看日K线。周期越长越难被人为操纵,其突破往往代表重要趋势的变化。

俗话说,会买的是徒弟,会卖的是师傅。平仓了才能把账面利润变成实际利润。什么时候卖,确实是一个很复杂的问题。卖早了,可能价格涨了10倍,自己只赚了1倍,卖晚了,辛辛苦苦的利润化为灰烬。我也没法告诉你这个问题的答案,因为我也不知道。但在市场疯狂地时候,卖总是没错的。市场成交量放大,价格飞速上涨的时候,就是市场疯狂的时候。比如今年5月份的A股,比如13年底的比特币。这时候就是要最小心的时候了,一旦价格出现巨大回落,就要准备离场了。

2014~2015 年的A股:

2013~2014 年的比特币:

2015年末的比特币:

深圳车牌竞价分析

前不久拿到了驾照,就琢磨着买辆代步车。但现在深圳车牌限号,买车需要有车牌指标,车牌指标可以通过摇号或竞价获得。看了一下上期摇号结果,中签率不到1%,平均需要接近9年才能中签。并且从往期来看,参与摇号的人数是越来越多的,中签的概率会越来越低,入下图所示:(数据来源:http://xqctk.sztb.gov.cn/gbl/index.html

摇号人数

所以目前来看,通过竞价是比较靠谱的获取车牌指标的方式,所以研究了一下过去所有8期的车牌竞价数据。车牌竞价本质上也是一种公开市场,卖方为市政府,买方为有购车需求者,买卖标的为车牌指标。市场的价格通常是由供需共同决定,但这个市场供给是固定的,那么影响价格走势的就是需求的变化了。

如果政策保持不变,长期来看,积累的有购车需求的人会越来越多,那么势必会推高车牌的竞价价格。但短期来看,影响车牌竞价价格的因素很多,除了供需之外,还有人们的情绪。既然是一种公开市场,那么短期的价格走势就可以通过技术分析的手段进行分析。

技术分析就是对过往成交的量价分析。从官网的公告中整理了感兴趣的一些数据,分别是投放指标数,竞拍人数,最低价,平均价,成交量。

QQ20151009-1@2x

其中除了最早2期因为政策刚开始施行,供给大于需求之外,之后的几期都是供给小于需求的,这也将是常态,所以研究投放指标和成交量意义不大。那么这里研究的量应该为参与竞拍人数,而最低价最能反映该市场的有效价格。下图为量价走势:

竞拍人数与最低价

从上图可以清晰的看出,从第3期到第6期,参与竞拍人数和最低价是同步上升的,典型的量价齐升。从第7期开始,参与人数开始下滑,但价格仍然继续攀高到了5w,出现量价背离现象。到第8期,参与人数进一步下滑,最低成交价也大幅跳水。我们可以从参与者心理来分析这种现象:如果往期车牌价格走高,但在自己心理价位之内,由于会担心车牌价格继续走高,所以会选择高价竞拍车牌,这会进一步推高价格;但如果车牌价格超过了自己心理价位,会选择放弃短期内购车的欲望,通过摇号去碰运气。从走势来看,转折点在第六期,平均成交价接近3w,这说明3w是目前市场参与者的一个平均心理价位。

由于竞价市场的特殊规则,最低价并没有太大参考价值,平均价才能反映出参与者实际付出的价格。在一个有效的市场中,最低价和平均价应该很接近才比较正常,下图为最低价和平均价的走势:

最低价与平均价

可以看出从第3期到第7期,最低价和平均价都比较接近。但在第8期,最低价与平均价之间的差额极为悬殊,这种极端情况肯定是不可持续的。仔细看下官方的公告,还有这样一个数据:实际参与报价的人数为3016个。而车牌数量为2945个,两者差额非常小。但因为参与者并不知道该情况,参与者能获取到信息只有两次播报的平均报价。参与者强烈的购车需求导致平均价仍然超过了5w。这让我联想到了股票市场上的曾经出现的逼空行为:股票价格连续上涨,远远超出了其实际价值,于是开始有人对其大量抛空,由于当时可以裸空,实际卖空数量甚至超出了股本数,这时有人用大量的资金不计代价的继续拉高股票,买光了市场中所有流动股票,卖空者为了避免破产,不得不计代价从逼空者手中买回股票以履行合约。车牌价格连续4个月上涨,强买车需求者不得不计代价的拍入车牌,这也算是一种逼空行为。极端情况总是不会持续太久的,最高价与平均价的大幅偏离肯定会被市场修复。

由于上期最低价很低,低于了很多人的心理价位,会有很多潜在需求者从摇号转为竞拍,所以接下来参与竞拍的人数可能会上升,这会让市场变得更加有效,最低价会上升。目前市场平均心理价位在3w左右,但在过去5期的逼空行情中,愿意出高价的参与者已经消耗殆尽,所以短期内平均成交价可能会降低到2w到3w之间。长期来看,有购车需求的人会越来越多,竞拍价格可能会继续上涨。所以,如果半年内有购车计划的话,在接下来几期内竞拍车牌应该是比较划算的。

传数字问题

昨天去上课,期间做了一个我觉得很有意思的游戏:传数字游戏。游戏的规则是这样的:每个小组站成一纵队,从后面向前面传输一个数,但队员之间不能说话,不能打手势,只能通过“砍”和“揪”两种动作向前传递信息。之前在入职时玩过一个类似的游戏,但只是规定不允许说话。

其实这是一个很经典的信息编码问题:把一个数字编码成为“砍”和“揪”两种动作。另外由于事先并不知道要传输哪些数字,所以要编码时要考虑到很多情况,比如负数和小数点等。

游戏一共进行了三轮,数字也越来越复杂。前两轮时等数字从后面传递到前面,已经面目全非了,几乎没有一个小组能正确完整的把数字从队尾传递到对头。不过经过两轮的迭代,不断的优化编码规则,最后一轮我们小组终于能够又快有准确的把数字传递到前面。

我觉得最重要的编码准则是:简单、稳定和快速。

首先,“简单”是最重要的。编码规则一定要简单到几句话就能说清楚,不违反人的直觉,只有少数几种特殊情况,这样才能让大家都准确的记住并理解。一个反例就是有一个小组在总结“失败”经验时说道,他们画了一个很大的流程图,考虑到了各种情况,有很多分支,但没几个人能记清楚规则,导致信息的翻译错误。并且还说,如果是让计算机来模拟的话肯定是没问题的。可问题是人很难达到计算机那样精确。

其次是“稳定”。对于一个程序员来说,“砍”和“揪”很容易让我联想到了计算机中的“0”和“1”。计算机选择了使用二进制而非其他进制来表述数据是很有道理的,因为“0”和“1”分别可以对应开关的“关”和“开”,或者电压“低电压”和“高电压”或者“有磁性”和“无磁性”,他们之间的差别很明显,可以很容易的区分开来。反之,如果计算机用十进制来存储的话,比如分别用1v电压表示1,2v电压表示2等等,这样一旦遇到电压不稳的情况有出现错乱了。另一个小组在分享“失败”经验时说道,他们制定的规则是用砍和揪身体的不同部位代表不同的含义,比如揪一下袖子代表5等,但正好有一个女生穿了无袖衣服。另外有人揪了前面一个人某一个部位,结果前面的人确理解成了另一个部位。虽然最后还有一个队使用类似的办法也成功的传递了数字,但是如果队伍再长一点的话,恐怕就很容易出差错了。

最后是“快速”。这个之所以排在最后是因为错误信息传递的再快仍然是错误的。只有在保证了准确和稳定性的前题下,才可以追求速度。在最开始我们采取的策略是只有后一个人把所有信息都传递完后,再传递给前面一个。这样就很慢,并且大部分人都只是在等待。后来优化为每收到一个数字就马上传递给前面一个人,而不是等待所有数字传递完。这样中间的人其实成为了管道,只需要队尾了对头两个人知道规则分别进行编码和解码即可。

经过三轮的迭代优化后,我们的编码规则是这样的:用“砍”代表数字,连续“砍”前面一个人的肩膀多少下就代表对应的数字。用“揪”代表特殊情况,比如“揪”一下代表数字0,连续“揪”两下代表小数点,连续“揪”三下代表负号等,每个符号中间暂停一段时间。比如 -0.285 就编码成了:揪三下 揪一下 揪两下 砍两下 砍八下 砍五下。只要不数错,基本不会出现差错。

C 读取 ini 配置文件

ini 是一种很有用的配置文件格式,最初出现在 Windows 操作系统上,特别是其支持两级配置项,扩展起来很方便。相比于 XML 配置文件,又很轻量并且清晰易读。当然,如果需要多级的配置项,用 XML 是个很好的选择。

最近做一个项目准备使用 ini 作为配置文件格式,找来找去没找到一个趁手的 C 语言的 ini 配置文件解析器,如果认真找的话应该也能找到,但抑制不住造轮子的欲望,于是我自己用 C 写了一个 ini 配置文件解析器。简单期间,不支持写操作,只支持读操作。项目地址在此:https://github.com/haipome/ini

它支持基本的 ini 语法,即:

[section]

标识一个段的开始,直到下一个段开始或文件结束都属于这个段。

name=value

标识一个属性。

另外,它还有一下特征:

1、支持全局属性,即如果属性在任何段定义都没有出现时,那么它是全局的,放在 “global” 段里。在查询时,section 参数如果为 NULL 或空字符串,那么就在全局段里找。当然,你也可以显式的的写出 [global] 段。

2、段名,属性名和属性值没有长度限制,最大限制取决于内存大小。

3、段名和属性名的命名没有特殊限制,你甚至可以用使用汉字。当然,属性名内不能包含 ‘=’,另外它们周围的空白字符会被去掉,内部是可以包含空白字符的。

4、空行,包括只含有空白字符的行会被自动忽略。

5、如果行以 ‘;’ 或 ‘#’ 开始(如果前面有空白的话忽略),则该行也被忽略,可以用来提供注释。

6、如果一个段在前面已经出现过,那么自动把它们合并在一起;如果在一个段内,一个属性名已经出现过,那么它会覆盖原有的值。

7、换行符可以用 ‘\’ 转义,这样你可以把一个很长的行拆开来写。

提供的 API 中有一些很方便的功能,可以直接读取一个整数或浮点数,也可以直接读取一对 IP : Port 地址。

非常欢迎 fork 和 pull request.