前言:
  之前讲到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. jquery 浮动 固定显示

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>无标题文档 我爱b ...

  2. [LeetCode] 26. Remove Duplicates from Sorted Array ☆(从有序数组中删除重复项)

    [LeetCode] Remove Duplicates from Sorted Array 有序数组中去除重复项 描述 Given a sorted array nums, remove the d ...

  3. gcc/g++编译器的安装与说明

    gcc/g++编译器的安装与说明 1.gcc/g++编译器的安装 gcc yum install gcc g++ yum install gcc-c++ 2.gcc/g++的作用 将c/c++源代码编 ...

  4. 安装 yaml-cpp,MP4V2

    一.在ubuntu上安装yaml-cpp的过程: git clone https://github.com/jbeder/yaml-cpp.git进入yaml-cpp目录后,mkdir buildcd ...

  5. What to do when you have small dataset - 拥有小型数据集时该怎么办

    I'm trying to train a classifier with neural network, but I've got too small datasets. Each class ha ...

  6. 使用 spring封装的javamail linux服务器发送邮件失败解决

    原文参考:https://blog.csdn.net/a540891049/article/details/79385471 由于某些平台的linxu服务器为了安全起见 屏蔽了发送邮件的常用端口 25 ...

  7. bash配色

    Table of Contents PS1格式 基本格式 其它可能的格式 PS1配色方案 配置文件 bash的命令提示符和终端外观由环境变量PS1定义 PS1格式 基本格式 \u 显示当前用户名 \h ...

  8. Shadow Properties之美(二)【Microsoft Entity Framework Core随笔】

    接着上一篇Shadow Properties之美(一),我们来继续举一个有点啰嗦的栗子. 先看简单需求:某HR系统,需要记录员工资料.需要记录的资料有: 员工号(规则:分公司所在城市拼音首字母,加上三 ...

  9. 关于Opengl投影矩阵

    读 http://www.songho.ca/opengl/gl_projectionmatrix.html 0.投影矩阵的功能: 将眼睛空间中的坐标点 [图A的视椎体]     映射到     一个 ...

  10. python简单爬虫 用beautifulsoup爬取百度百科词条

    目标:爬取“湖南大学”百科词条并处理数据 需要获取的数据: 源代码: <div class="basic-info cmn-clearfix"> <dl clas ...