Dapp混合模型开发--Dice2win的解读
前言:
之前讲到Dapp原生态对随机函数的支持并不友好, 现在讲讲一种解决思路. 既能保证随机函数的不可预测性, 又能保证公平性, 平台和玩家都能满意. 而Dapp中的Dice2Win实现, 刚好是其中的一个经典例子.
案例:
在讲具体的思路前, 来讲一下一个经典的案例:
两人分一个苹果, 切成两半分, 不过两人足够理性且追求自身利益的最大化, 请问有什么策略保证最大的公平性呢?
猜拳定胜负, 然后由胜利者主导分苹果吗? 哈哈, 这个答案显然不合适.
说起这个例子来, 笔者印象也很深, 好想是央视有个节目李开复出的题, ^_^, 也不小心暴露了年龄.
答案是: 让一个人来切苹果, 然后让另一个人先挑.
先挑的人, 总是能获取最好的半个苹果, 而切苹果为了不让自己利益受损, 它会尽量保证苹果公平的被切开.
从这个案例中, 我们或许能得到一些启示, 所谓的公平, 没有所谓先发优势, 只有纳什均衡的平衡点.
思路:
Dice2Win的思路和上述的例子类似, 它采用混合模式, 巧妙地解决随机数弱, 且容易被预测的问题. 其整个流程如下:

1. 玩家指定行动计划, 并生产对应的hash值.
2. 服务端收到玩家的hash值, 产生随机值reveal, 然后根据reveal生产commit值, 把这个返回给玩家
3. 玩家带着commit和行动信息, 在智能合约下真正下注
4. 服务端发起结算, 带着真正的reveal值去结算
中间的行动计划和reveal没法中途修改, 因为有hash值的验证
其本质的思想是hash-commit-reveal, 其核心的思想是: 服务端不知道玩家的行为, 玩家不知道服务端真正的随机数. 而最终结果在合约里验证hash, 并给出预期的结果. 这样的流程, 保证玩家和服务端都满意.
代码:
具体的Dice2Win代码在这, 我们来简单解读一下.
placeBet代码片段:
function placeBet(uint betMask, uint modulo, uint commitLastBlock, uint commit, bytes32 r, bytes32 s) external payable {
Bet storage bet = bets[commit];
require (bet.gambler == address(0), "Bet should be in a 'clean' state.");
// Validate input data ranges.
uint amount = msg.value;
require (modulo > 1 && modulo <= MAX_MODULO, "Modulo should be within range.");
require (amount >= MIN_BET && amount <= MAX_AMOUNT, "Amount should be within range.");
require (betMask > 0 && betMask < MAX_BET_MASK, "Mask should be within range.");
// Check that commit is valid - it has not expired and its signature is valid.
require (block.number <= commitLastBlock, "Commit has expired.");
bytes32 signatureHash = keccak256(abi.encodePacked(uint40(commitLastBlock), commit));
require (secretSigner == ecrecover(signatureHash, 27, r, s), "ECDSA signature is not valid.");
uint rollUnder;
uint mask;
if (modulo <= MAX_MASK_MODULO) {
// Small modulo games specify bet outcomes via bit mask.
// rollUnder is a number of 1 bits in this mask (population count).
// This magic looking formula is an efficient way to compute population
// count on EVM for numbers below 2**40. For detailed proof consult
// the dice2.win whitepaper.
rollUnder = ((betMask * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO;
mask = betMask;
} else {
// Larger modulos specify the right edge of half-open interval of
// winning bet outcomes.
require (betMask > 0 && betMask <= modulo, "High modulo range, betMask larger than modulo.");
rollUnder = betMask;
}
// Winning amount and jackpot increase.
uint possibleWinAmount;
uint jackpotFee;
(possibleWinAmount, jackpotFee) = getDiceWinAmount(amount, modulo, rollUnder);
// Enforce max profit limit.
require (possibleWinAmount <= amount + maxProfit, "maxProfit limit violation.");
// Lock funds.
lockedInBets += uint128(possibleWinAmount);
jackpotSize += uint128(jackpotFee);
// Check whether contract has enough funds to process this bet.
require (jackpotSize + lockedInBets <= address(this).balance, "Cannot afford to lose this bet.");
// Record commit in logs.
emit Commit(commit);
// Store bet parameters on blockchain.
bet.amount = amount;
bet.modulo = uint8(modulo);
bet.rollUnder = uint8(rollUnder);
bet.placeBlockNumber = uint40(block.number);
bet.mask = uint40(mask);
bet.gambler = msg.sender;
}
settleBet代码片段:
function settleBet(uint reveal, bytes32 blockHash) external onlyCroupier {
uint commit = uint(keccak256(abi.encodePacked(reveal)));
Bet storage bet = bets[commit];
uint placeBlockNumber = bet.placeBlockNumber;
// Check that bet has not expired yet (see comment to BET_EXPIRATION_BLOCKS).
require (block.number > placeBlockNumber, "settleBet in the same block as placeBet, or before.");
require (block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM.");
require (blockhash(placeBlockNumber) == blockHash);
// Settle bet using reveal and blockHash as entropy sources.
settleBetCommon(bet, reveal, blockHash);
}
具体的解读还是留给用户自己哈, ^_^.
攻击:
当然这种模式也有一定的缺点, 比如服务中止攻击. 即玩家placeBet后, 其行动信息在链上可见, 这时服务可以提前预知结果, 若输了, 可以中止settleBet的调用. 因为玩家不清楚对方到底是那个随机数, 只是看到该下注一直处于pending状态.
所以有学者也觉得Dice2Win理论上, 也不是一个真正意义上公平游戏, 具体参见博文: Not a fair game, Dice2win公平性分析.
总结:
其实我想平台为了长久发展, 是不太做这种伤信誉的事的. 总的来说, hash-commit-reveal这种机制, 还是相当不错的, 我看到不少的混合模型的dapp, 采用这种模式来保证游戏的公平性.
Dapp混合模型开发--Dice2win的解读的更多相关文章
- 在区块链侧链上进行Dapp技术开发
我在白皮书里提到过,asch使用的是不同于以太坊和比特币的侧链架构,dapp是运行在侧链上的,每套侧链对应一个dapp. 侧链的独立性 侧链架构的好处是代码和数据独立,不增加主链的负担,避免数据过度膨 ...
- 以蓝牙开发的视觉解读微信Airsync协议
微信硬件平台使用蓝牙作为近场控制的连接件,并拟定了<微信蓝牙外设协议>.这份协议更像一个标准,用于规范微信和蓝牙外设之间的数据交互场景和接口.但从开发者来看,要完全读懂这份协议,恐怕需要熟 ...
- 链上链下交互 以太坊Dapp接口开发
主要是指的是用NodeJs调用 提供接口供前端使用 用户查询和转账 以太坊Dapp项目 众筹项目 功能需求 路人 查看所有众筹项目, 2 @ OK 根据众筹项目的address获取该众筹的详情 (参与 ...
- 前端开发 Vue -4promise解读1
JS(JavaScript) - Promise 2015年6月, ES2015(即 ECMAScript 6.ES6) 正式发布.其中 Promise 被列为正式规范,成为 ES6 中最重要的特性之 ...
- iOS开发-单例模式的解读
现在网上的有很多人写单例模式,一个很基本的东西但是版本也有很多,新人看了难免有些眼花缭乱的感觉.自己最新比较闲,也过来写一些自己的心得. 在往下看之前,我们要明白一点,那就是在什么情况下我们才要用到单 ...
- 微信小程序开发--flex详细解读(2)
一.align-items和其参数 stretch / baseline 注:sretch只有在交叉轴没有设置固定长度的情况下才有作用 ...
- 微信小程序开发--flex详细解读
一.结构:flex布局 是由一个大的容器加上多个子元素组成. <view class="container"> <view </view> <v ...
- 前端开发 Vue -4promise解读2
https://www.runoob.com/vue2/vue-tutorial.html promise promise是什么? 1.主要用于异步计算 2.可以将异步操作队列化,按照期望的顺序执 ...
- 如何从零开始学习区块链技术——推荐从以太坊开发DApp开始
很多人迷惑于区块链和以太坊,不知如何学习,本文简单说了一下学习的一些方法和资源. 一. 以太坊和区块链的关系 从区块链历史上来说,先诞生了比特币,当时并没有区块链这个技术和名词,然后业界从比特币中提取 ...
随机推荐
- decode函数解决oracle报错"除数为0"的问题
公司的网站在运行的时候突然报错打不开了,打开一看发现报了一个错:ORA-01476:除数为0. 网上一搜发现还是挺多人遇到这个问题的,解决办法就是用decode函数. decode是oracle内置的 ...
- mlp_clf_mnist_test
import os os.environ['CUDA_VISIBLE_DEVICES'] = "0" from mlp_clf import MLPClassifier impor ...
- 相似的RGB颜色——算法面试刷题3(for google),考察二分
在本题中,每个大写字母代表从“0”到“f”的一些十六进制数字. 红绿蓝三元色#AABBCC可以简写为#ABC. 例如,#15c是颜色#1155cc的简写. 现在,假设两种颜色#ABCDEF和#UVWX ...
- SSM框架中如何简便上传文件表单
此种方式上传文件相对简单,以下均经测试成功,才提供到此. 以下为单个文件上传方式 分析:本次的工作目的是根据一级标题产生对应的二级标题,在每个二级标题下对应一个(file字段)新闻文件,当点击新闻文件 ...
- Spring中使用RedisTemplate操作Redis(spring-data-redis)
RedisTemplate如何检查一个key是否存在? return getRedisTemplate().hasKey(key); 由一个问题,复习了一下redis 抄自: https://www. ...
- 苹果手机的SB系列(4)你让我除了退出还能按哪个键
我不知道,他们哪里来的自信,自己的机子就不死机?不设置重新启动? 看看下面这个界面,我按哪个键,全部是灰色的! 今天还有一事纪念,0.4m高的坠地,外屏碎掉了.
- 小程序中通过判断id来删除数据,当数据长度为0时,显示隐藏部分(交流QQ群:604788754)
欢迎加入小程序交流群:本群定期更新在工作种遇到的小知识(交流QQ群:604788754) WXML: <!--遍历循环的数据部分--> <block wx:for="{{d ...
- python 面向对象 继承 派生 组合
具体参考博客:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label12 一.面向对象 面向对象:对象与对象之间的相互交互,不可预 ...
- 《Swell数学》用户故事
一.用户故事基础知识: 1. 从用户的角度来描述用户渴望得到的功能. 2. 用户故事是描述对用户有价值的功能,好的用户故事应该包括角色.功能和商业价值三个要素. 3. 一个用户故事只是以客户能够明白的 ...
- python中下划线的特殊用法
python下划线用法总结: ① _XXX 不能用于“ from model import * ”的导入: ②__XXX__ 系统定义名字: ③__XXX 类中的私有变量名. 总结:避免随意用下划线 ...