Solidity陷阱:以太坊的随机数生成

Solidity是一种相当新的语言,因为没有代码是完美的,它包含与代码相关的问题以及你希望用它完成的任务。本文将指导你使用随机数作为以太坊智能合约的输入时的最佳实践和陷阱。

Solidity随机数生成

Solidity无法创建随机数。实际上,每个创建随机数的算法都是伪随机的——没有语言能够创建完全随机的数字。Solidity的问题在于复杂的算法成本太高,因此使用了更基本的解决方案。除此之外,Solidity代码应该是确定性的,因为它将在多个节点上运行。我们需要一种能够生成一次随机数的算法,并在多个节点上使用它。像时钟时间这样的东西不能用于生成随机数,因此我们必须查看其他选项。作为开发人员,你应该了解此问题,因为攻击者能够在某些特定情况下预测结果。

最常用的算法之一是“线性同余发生器”(LCG)。它是最古老的算法之一,快速且易于理解。LCG是嵌入式系统的一个很好的选择,因为它们的内存有限。但是,它不适合加密安全应用程序。虽然,这仍然在智能合约中使用,因为快速算法在气体成本方面实施起来便宜得多。

算法本身执行以下步骤:

  • 接受输入。
  • 在输入上执行算法。
  • 取输出模数(除以你需要的范围内的最大数量)。
  • 在你需要的范围内输出0到最大数字。

让我们探讨使用彩票智能合约示例创建随机数的不同方法。用户可以通过向合约发送0.1以太以及0到250之间的整数来加入彩票。

1.Block.timestamp&Block.difficulty

每当他确认交易时,矿工就会分配一个block.timestamp。我们的彩票合约的任何玩家都无法控制它。让我们看看这段代码来创建一个随机数。

1
2
3
function random() private view returns (uint8) {
return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251);
}

这段代码首先hash了一个块时间戳和难度。接下来,我们将hash转换为整数并将其除以251以获得0到250之间的整数。但是,这段代码的问题在于我们不应该信任矿工来挑选胜利者。

2.彩票输入任意数据

我们需要更多任意数据来挑选我们的赢家。我们可以使用已经进入我们的彩票智能合约的玩家的地址,但是我们必须将其隐藏在其他玩家之外,因为他们可以滥用它。隐藏此信息是不可能的,因为它全部记录在区块链上。

提交给我们的彩票智能合约的号码可以使用。用户必须将他们选择的号码与他们的以太坊地址一起hash。这给了我们一个相当随机的数字。

3.其他机制

3.1以太坊闹钟

开发人员需要考虑何时选择胜利者。时间之类的东西在以太坊虚拟机中不可用,因为代码将在不同的时间在多个节点上运行。这使得挑选胜利者变得更加困难。实现这一目标的一种方法是在智能合约中实施一项功能,该功能将关闭彩票并选择获胜者。这不像我们希望的那样去中心化。合约的所有者在确定他们的朋友将获胜时可以关闭彩票。我们想避免这种作弊行为。

更好的选择是使用以太坊闹钟。它是一种允许稍后在以太坊区块链上执行调度事务的服务。这项服务完全没有信任,这意味着整个服务作为智能合约运作。基本上,以太坊闹钟使用块号来安排交易。注意,这并不意味着合约本身就会被唤醒。它依赖于有兴趣的用户(以太奖励)来调用“挑选获胜者”功能。当然,如果没有人打电话给你的功能,你的彩票就会失败。

3.2随机数据输入

Random.org提供了一个API,通过JSON为你提供随机数据源。以太坊智能合约可以使用此数据源来提供选择随机数的算法。由于安全性很重要,因此可以使用数字签名。随机数据将由Random.org签署。你可以验证数据的完整性,以便证明它确实来自Random.org并且数据未被篡改。

RANDAO是区块链领域的一个新项目,专注于提供随机数。他们使用oracles和智能合约的组合为你提供随机数字。但是,RANDAO服务目前相当缓慢。如果你拥有经常使用的应用程序,这并不理想。

3.3 Blocknumber Watcher

你还可以在代码中使用观察程序,它会检查程序段编号,直到它与你设置的目标编号相匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function f( blocknumber, to_address, value_) { 
var filter = web3.eth.filter('latest').watch(
function(err, blockHash) {

var target=blocknumber;

if(web3.eth.blockNumber==target) {
filter.stopWatching(); // your function here
web3.eth.sendTransaction({to:to_address, from:web3.eth.coinbase, value: web3.toWei(value_,"ether")});
filter = null;

console.warn('Block reached');

if (callback) return callback(false);
else return false;

} else {
console.log('Waiting the block');
}
});
};

3.4 iOlite智能合约创建

iOlite正在创建一种接受自然语言来创建智能合约的产品。它使用称为快速自适应引擎(FAE)的斯坦福自然语言处理(NLP)引擎。iOlite依靠Solidity专家的社区培训。Solidity专家(贡献者)可以定义包含一个或多个句子的结构,并将其附加到相应的智能合约代码。

斯坦福NLP引擎的创建是为了理解复杂的语言。语言复杂程度取决于机器培训的数量。经过适当的培训,引擎将能够创建复杂的智能合约。FAE能够创建此类合约,因为复杂的合约实际上并不复杂。专家可以将请求拆分为多个较小的代码并将其附加到一个句子中。

当有人输入多个句子时,它会寻找相应的结构/句子来建立“复杂”的合约。贡献者将通过新结构的挖掘过程获得iOlite代币奖励。

使用iOlite的好处是智能合约专家可以像生成随机数一样为你解决难题。你可以在iOlite.io上找到更多信息。

结论

如你所见,生成真正的随机输入并非易事。不要依赖block.timestamp,现在和block.blockhash作为随机源。一个好的解决方案包括几个伪随机数据输入的组合以及使用oracles或智能合约来使其更可靠。你需要100%确定没有人可以篡改输入智能合约的数据。

在实现随机数生成逻辑之前要小心并三思而后行。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文Solidity陷阱:以太坊的随机数生成