前言:
  之前讲到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的解读的更多相关文章

  1. 在区块链侧链上进行Dapp技术开发

    我在白皮书里提到过,asch使用的是不同于以太坊和比特币的侧链架构,dapp是运行在侧链上的,每套侧链对应一个dapp. 侧链的独立性 侧链架构的好处是代码和数据独立,不增加主链的负担,避免数据过度膨 ...

  2. 以蓝牙开发的视觉解读微信Airsync协议

    微信硬件平台使用蓝牙作为近场控制的连接件,并拟定了<微信蓝牙外设协议>.这份协议更像一个标准,用于规范微信和蓝牙外设之间的数据交互场景和接口.但从开发者来看,要完全读懂这份协议,恐怕需要熟 ...

  3. 链上链下交互 以太坊Dapp接口开发

    主要是指的是用NodeJs调用 提供接口供前端使用 用户查询和转账 以太坊Dapp项目 众筹项目 功能需求 路人 查看所有众筹项目, 2 @ OK 根据众筹项目的address获取该众筹的详情 (参与 ...

  4. 前端开发 Vue -4promise解读1

    JS(JavaScript) - Promise 2015年6月, ES2015(即 ECMAScript 6.ES6) 正式发布.其中 Promise 被列为正式规范,成为 ES6 中最重要的特性之 ...

  5. iOS开发-单例模式的解读

    现在网上的有很多人写单例模式,一个很基本的东西但是版本也有很多,新人看了难免有些眼花缭乱的感觉.自己最新比较闲,也过来写一些自己的心得. 在往下看之前,我们要明白一点,那就是在什么情况下我们才要用到单 ...

  6. 微信小程序开发--flex详细解读(2)

    一.align-items和其参数  stretch / baseline 注:sretch只有在交叉轴没有设置固定长度的情况下才有作用                                 ...

  7. 微信小程序开发--flex详细解读

    一.结构:flex布局 是由一个大的容器加上多个子元素组成. <view class="container"> <view </view> <v ...

  8. 前端开发 Vue -4promise解读2

    https://www.runoob.com/vue2/vue-tutorial.html promise promise是什么?   1.主要用于异步计算 2.可以将异步操作队列化,按照期望的顺序执 ...

  9. 如何从零开始学习区块链技术——推荐从以太坊开发DApp开始

    很多人迷惑于区块链和以太坊,不知如何学习,本文简单说了一下学习的一些方法和资源. 一. 以太坊和区块链的关系 从区块链历史上来说,先诞生了比特币,当时并没有区块链这个技术和名词,然后业界从比特币中提取 ...

随机推荐

  1. 李航《统计学习方法》CH01

    CH01 统计学方法概论 前言 章节目录 统计学习 监督学习 基本概念 问题的形式化 统计学习三要素 模型 策略 算法 模型评估与模型选择 训练误差与测试误差 过拟合与模型选择 正则化与交叉验证 正则 ...

  2. MongoDB之 分组查询

    分组查询 可视化工具 https://robomongo.org pymongo from pymongo import MongoClient # 方式一: c = MongoClient(host ...

  3. FormData上传文件(input file)

    <div> <input type="file" name="FileUpload" id="FileUpload" va ...

  4. BATJ面试指南

    Java并发编程面试题汇总 线程 线程是一个独立执行的调用序列,同一个进程的线程在同一时刻共享一些系统资源(比如文件句柄等)也能访问同一个进程所创建的对象资源(内存资源).java.lang.Thre ...

  5. js检测页面离开

    window.location = 'yjk://app.h5.ihaozhuo.com?page=livetrailer&videoLiveId=' + parseInt(this.Requ ...

  6. php中微信开发的转发分享

    简单来说  ,一共四步 1.  微信公众平台中公众号设置”的“功能设置”里填写“JS接口安全域名”.该域名填写你的项目的域名. 2. 下载jssdk的damo,https://mp.weixin.qq ...

  7. Failed to install the hcmon driver

    在安装虚拟机的时候出现“Failed to install the hcmon driver”错误,是之前VM没有卸载干净,提供两个参考解决方法: 1:在C盘的驱动文件夹也就是“C:\Windows\ ...

  8. day42-python消息队列一

    消息队列”是在消息的传输过程中保存消息的容器.消息队列最经典的用法就是消费者和生成者之间通过消息管道来传递消息,消费者和生成者是不通的进程.生产者往管道中写消息,消费者从管道中读消息.操作系统提供了很 ...

  9. 大数据之NBA

    2017年NBA季后赛落幕后,网络上仍有大量关于NBA关键词的搜索. 这是近30天来,通过PC端和移动端搜索的趋势,可以看到有些日期的搜索指数是猛增的,因为NBA有大新闻爆出,比如8月23日,骑士与凯 ...

  10. Python语言:Day9练习题及其答案

    1.使用while循环输出1,2,3,4,5,6, 8,9,10 #!/usr/bin/python3 n = 1 while n <= 10: if n != 7: print(n) else ...