前言 上个月BCH进行了升级,开放了一些操作码。很多人都有疑问,开放了这些操作码能干什么?这里就以ChainBet协议为例,来探究BCH的脚本能力。
ChainBet 来历 ChainBet协议的作者是Jonald,同时他也是著名的BCH钱包Electron Cash的主要开发者。就在几天前,Jonald提出了ChainBet的思路,并写了协议草稿。然后Open Barzzar的主要开发者Chris就在Yours.org上实现了一个Demo。没错,程序员就是这么简单粗暴,直接干出代码来给你!
简介 ChainBet协议的目的是实现二人链上打赌,不需要第三方并且没人能赖账。协议主要分两部分:
链上沟通,通俗的说就是”聚众“
链上打赌,通俗的说就是”赌//博“
没错,ChainBet通过BCH区块链把这两件事都完成了。“聚众”这事咱们找个其他时间再说,今天主要分析是如何做到不需要第三方并且还没人能赖账的。
原理 背景知识 先介绍一下会贯穿我们整个文章的两个主人公,他们就是在小学语文造句里频繁出场的小明和小红,但今天他们有了洋气的外国名:
Alice
Bob
Alice和Bob两个人毫无来由地突然想打赌了,事情的发展就是这么突兀。规则很简单:
两人每个人都偷偷写下一个数字
然后两个人同时亮出数字,把数字相加
偶数Alice赢,奇数Bob赢
他们的“赌具”是人手一个BCH钱包客户端,“赌资”就是客户端里的BCH。(好了,作者已经没心思扯淡了,接下来要进入技术环节了,请硬着头皮勇敢地看下去)
方案推演 假设咱们让Alice和Bob把BCH打入到一个P2SH地址里,如果Bob赢了,那么Bob拿到Alice的数字,通过数字和Bob的签名把币转到自己地址;如果Bob输了,那么通过time lock功能,过一段时间Alice可以把币拿走。
听上去不错。但是,有个问题:Alice既然知道过一段时间自己可以把币转走,那她完全可以不把自己的数字给Bob,静静等待币归自己。所以,这个方法行不通。
那么我们能不能做到,如果Alice想玩这个游戏,就不得不给Bob展示她的数字呢?可以!这么干:
双方用钱包生成一个随机数字,并分别公开自己数字的Hash值,这样既不用暴露数字,又保证不能更改数字。我们把公开的Hash值称之为aliceCommitment和bobCommitment。
Alice先创建一个P2SH地址,这个地址的币,需要Alice提供她的数字和私钥签名才可以转出。我们把这个地址称之为Alice托管地址。当然,Alice需要提供赎回脚本给Bob,Bob检查这个地址的脚本是否正确。
画重点:这个地址里的币还是归Alice控制,但是如果Alice要从这个地址转出币,就一定需要提供自己的数字。也就是说,一旦这个地址里的币被转出,转账广播到区块链上,那么Bob就知道了Alice的数字。
Alice转币到Alice拖管地址。
Bob生成一个P2SH地址,我们称之为赌局地址,这个地址的脚本规定只有赢方才可以拿走币。当然,Bob需要提供赎回脚本给Alice,Alice检查这个地址的脚本是否正确。
Bob生成一笔转账,输出是到赌局地址,输入有两个:
第3步中的Alice托管地址那笔转账的输出,这需要Alice的签名,Bob可以构造转账,但不能签名。
Bob自己钱包的输入,并且签名。
Bob把上一步中构造的转账数据发给Alice,请Alice签名。
Alice收到转账数据,确认没问题后签名,为了让转账有效,同时也需要提供自己的数字。然后广播到网络,此时Alice和Bob的币都转入赌局地址。
Bob收到上一步的广播,从中获得了Alice的数字,再加上自己的数字,Bob知道了两个数字。
如果两个数相加是奇数,那么Bob赢了,他就可以用这两个数字和自己的签名,把赌局地址里的币提走了。
如果两个数相加是偶数,那么Bob输了,他可以什么也不管了,因为一段时间过后,Alice就可以把币转走。当然,如果Bob人够好,他可以立刻把自己的数字给Alice,让Alice马上把把币转走。
到此为止,问题解决了。
脚本 代码不会骗人,我用脚本来说明上述过程是如何实现的。脚本中的//后面的内容是我的解释
Alice托管地址的脚本:
OP_HASH160 //Alice提供她的数字,然后对数字进行Hash,得到Hash-A OP_EQUALVERIFY //比较Hash-A与第1步Alice提供的aliceCommitment是否相同,确保确实是Alice的数字 OP_CHECKSIG //检查Alice提供的签名,确保确实是Alice授权了转账 赌局地址的脚本:
OP_IF //如果Alice赢 OP_IF //如果Alice可以提供Bob的数字 OP_HASH160 OP_EQUALVERIFY //Alice提供Bob的数字,Hash后与bobLosingCommitment //比较,确保Alice没有随便拿个数字来瞎忽悠 OP_ELSE //如果Alice不能提供Bob的数字,但赌局已经结束一段时间,也可转走币 //相当于Bob输了,但是没有把数字给Alice "6 blocks" OP_CHECKSEQUENCEVERIFY OP_DROP //确保赌局已经结束了等于或超过6个块(1小时) OP_ENDIF OP_CHECKSIG //检测Alice的签名,确保来转账的是Alice,然后币就可以转走了 OP_ELSE //如果Bob赢 OP_DUP OP_HASH160 OP_EQUALVERIFY //确保Bob可以正确提供自己的数字 OP_OVER OP_HASH160 OP_EQUALVERIFY //确保Bob可以正确提供Alice的数字 OP_4 OP_SPLIT OP_DROP OP_BIN2NUM OP_SWAP OP_4 OP_SPLIT OP_DROP OP_BIN2NUM //把两个数字转换成可计算的整数 //其中OP_SPLIT是5月份升级后才打开的操作码 OP_ADD OP_2 OP_MOD OP_0 OP_EQUALVERIFY //把两个整数相加,确定是偶数:除以2,余数是0 //其中OP_MOD是5月份升级后才打开的操作码 OP_CHECKSIG //检测Bob的签名,确保来转账的是Bob,然后币就可以转走了 OP_ENDIF 整个原理就是这样了,希望你已经看懂了。全部协议的脚本会更复杂,但如果上面的内容你可以理解,那理解全部协议就不成问题了。
结束语 BCH每年的5月份和11月份会例行进行两次升级,每次升级都会让网络功能更强大、更健壮。ChainBet用到的OP_SPLIT和OP_MOD就是5月份升级刚刚打开的。也就是说,ChainBet协议只有BCH网络可以实现,BTC网络不行。
BCH能够快速升级,离不开开发者们的努力。目前他们的收入并不多,在此我也呼吁大家给主要开发团队之一Bitcoin ABC的开发者捐助BCH,他们的捐助地址是:
qqeht8vnwag20yv8dvtcrd4ujx09fwxwsqqqw93w88