在智能合约中使用 ANU 的量子随机数生成器

为了满足智能合约对随机性的需求,去中心化伪随机数生成器是一种常用的方法。

照片由FLY:D发布在Unsplash上

随机数生成器(RNG)一直是使用智能合约时最大的问题之一。确定性虚拟机无法产生“真正的”随机性。

为了满足智能合约对随机性的需求,去中心化伪随机数生成器是一种常用的方法。最常用的方法之一是Chainlink的VRF或可验证随机函数,它在链上提供密码可证明的随机数。它生成一个链下随机数和用于验证结果的加密证明。

然而,这种配置与其他第三方预言机网络存在相同的问题。设置一个可以提供PRNG的预言机节点会暴露潜在的攻击载体,比如女巫攻击,也缺乏源透明性和去中心化。例如,需要信任治理实体来选择网络参与者,这意味着去中心化的PRNG只与治理实体一样安全和去中心化。

量子随机数生成

QRNG通过量子现象产生随机性。它使用一个“真正的”熵源,利用量子物理的独特特性来产生真正的随机性。

实现QRNG的方法各不相同,但共同点是得到的数字将是真正随机的,因为量子事件的结果在理论上是不确定的。因此,QRNG是随机数生成的黄金标准。

澳大利亚国立大学的QRNG Airnode

正如我们已经讨论过的,通过第三方预言机网络提供RNG会为攻击载体打开大门。但是由QRNG API提供商直接运营的第一方预言机 (airnode)会以最佳方式应对女巫攻击风险。

API3 QRNG是澳大利亚国立大学(ANU)提供的公共实用程序。它由ANU量子随机数托管的Airnode提供动力,这也意味着它是第一方服务。澳大利亚国立大学的量子光学部是该领域世界领先的研究机构之一。该部门还运行一个REST API,即量子随机数API,以服务于Web2中的QRNG。

它作为一种公共产品,所以也是免费的(除了gas成本),当需要链上RNG时,它通过一个易于使用的解决方案提供了“真正的”量子随机性。

Airnode和API3 QRNG是如何工作的?

https://docs.api3.org/qrng/introduction/how-works.html

首先,我们需要使用能够匹配上的赞助者钱包进行部署并赞助QrngRequester。QrngRequester将是检索随机数的主合约。

QrngRequester向AirnodeRrpV0提交一个随机数请求。Airnode从AirnodeRrpV0协议合约中收集请求,从链下检索随机数,并将其发送回AirnodeRrpV0。一旦接收到,它将使用随机数执行回调到请求程序。

编码QrngRequester.sol

开始

请确保已安装以下软件:

  • Node.js

  • yarn/NPM

另外,请确保已经克隆并安装了Airnode Monorepo。如果还没有,用以下命令克隆Airnode Monorepo:

$ git clone https://github.com/api3dao/airnode.git 

要安装依赖项,请执行以下步骤:

$ yarn run bootstrap

要构建所有的包,使用这个命令:

$ yarn run build

编制合约

为了编译QrngRequester合约,我们将使用Remix IDE。它是一个在线IDE,可以为与EVM兼容的区块链开发、部署和管理智能合约。

//SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol";

contract RemixQrngExample is RrpRequesterV0 {
    event RequestedUint256(bytes32 indexed requestId);
    event ReceivedUint256(bytes32 indexed requestId, uint256 response);

    address public airnode;
    bytes32 public endpointIdUint256;
    address public sponsorWallet;
    mapping(bytes32 => bool) public waitingFulfillment;

    // These are for Remix demonstration purposes, their use is not practical.
    struct LatestRequest { 
      bytes32 requestId;
      uint256 randomNumber;
    }
    LatestRequest public latestRequest;

    constructor(address _airnodeRrp) RrpRequesterV0(_airnodeRrp) {}

    // Normally, this function should be protected, as in:
    // require(msg.sender == owner, "Sender not owner");
    function setRequestParameters(
        address _airnode,
        bytes32 _endpointIdUint256,
        address _sponsorWallet
) external {
        airnode = _airnode;
        endpointIdUint256 = _endpointIdUint256;
        sponsorWallet = _sponsorWallet;
    }

    function makeRequestUint256() external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256.selector,
            ""
        );
        waitingFulfillment[requestId] = true;
        latestRequest.requestId = requestId;
        latestRequest.randomNumber = 0;
        emit RequestedUint256(requestId);
    }

    function fulfillUint256(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
{
        require(
            waitingFulfillment[requestId],
            "Request ID not known"
        );
        waitingFulfillment[requestId] = false;
        uint256 qrngUint256 = abi.decode(data, (uint256));
        // Do what you want with `qrngUint256` here...
        latestRequest.randomNumber = qrngUint256;
        emit ReceivedUint256(requestId, qrngUint256);
    }
}

QrngRequester有三个主要函数:setRequestParameters(), makeRequestUint256()和fulfillUint256()。

  • setRequestParameters()函数接受airnode、endpointIdUint256、sponsorWallet并设置这些参数。

  • makeRequestUint256()函数调用协议合约的airnodeRrp.makeFullRequest()函数,该函数将请求添加到其存储中并返回一个requestId。

  • 目标链下ANU Airnode收集请求并使用随机数向请求者执行回调。

请求参数

makeRequestUint256()函数需要以下参数发出有效请求。

  • airnode (地址)和endpointiduint256指定端点。

  • sponsorWallet指定将使用哪个钱包来完成请求。

响应参数

对QrngRequester的回调包含两个参数:

  • requestId:在发出请求时会被首次获取,并在这里作为参考传递,以识别响应所针对的请求。

  • data:在成功响应的情况下,这是已被编码的请求数据,除了其他响应数据外,还包含时间戳。使用abi对象中的Decode()函数对其进行解码,以获得随机数。

转到Remix IDE,创建一个合约,并将其粘贴到QrngRequester代码中。

现在,点击仪表板右侧的compile并编译智能合约。

部署合约

我们将把我们的QrngRequester部署到Goerli。确保钱包中有足够的测试网ETH来部署合约,并在以后资助sponsorWallet。

转到部署,运行交易,并在环境下选择“Injected Provider — MetaMask”选项。连接MetaMask。确保是在Goerli。

_rrpaddress是主airnodeRrpAddress。RRP合约已经部署在链上。

填充_rrpAddress之后,单击“Deploy”。确认MetaMask上的交易,并等待它部署Requester合约。

确保是在Goerli。

调用合约

当QrngRequester部署完成后,转到Deploy,运行交易,然后单击已部署合约下的请求者并下拉列表。

现在选择setRequestParameters并下拉菜单来设置所有的参数。

将以下内容添加到函数的相应字段中。

  • _airnode:所需QRNG服务提供者的airnode地址。从ANU Airnode查看它的值。

  • _endpointIdUint256: Airnode端点ID将返回一个随机数。从ANU Airnode查看它的值。

  • _sponsorWallet:一个由请求者合约地址、Airnode地址和Airnode xpub派生的钱包。这个钱包用来支付gas费用,以获得一个随机数。赞助者钱包必须使用命令derived -sponsor-wallet-address从Admin CLI中派生。使用命令输出的赞助者钱包地址的值。

在设置好Airnode CLI,安装并构建所有依赖项和包之后,运行以下命令来派生自己的_sponsorWallet。

Linux

npx @api3/airnode-admin derive-sponsor-wallet-address \
  --airnode-xpub xpub6CUGRUo... \
  --airnode-address 0xe1...dF05s \

  --sponsor-address 0xF4...dDyu9

Windows

npx @api3/airnode-admin derive-sponsor-wallet-address ^
  --airnode-xpub xpub6CUGRUo... ^
  --airnode-address 0xe1...dF05s ^

  --sponsor-address 0xF4...dDyu9

用一些测试网ETH资助sponsorWallet。单击交易按钮并确认交易以设置参数。

发出请求,单击makeRequestUint256按钮调用函数,并发出完整的请求。

现在可以前往并检查自己的新交易了。https://goerli.etherscan.io/sponsorWallet`

可能需要等待一段时间,因为Airnode调用AirnodeRrpV0.sol中的fulfill()函数,它将使用函数fulfillment functionid在fulfillAddress处回调请求者合约来传递数据(随机数)。

在这里,我们可以看到最新的fulfillment交易。

现在回到Remix并点击latestRequest按钮检查响应。

如果回调已经成功完成,randomNumber将会出现。waitingFulfillment的值将为假。

Source:https://medium.com/better-programming/a-guide-to-using-anus-quantum-random-number-generator-in-your-smart-contracts-21be5bed5aba

关于

ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。

本文首发于:https://mp.weixin.qq.com/s/5VBR-9XdNhxf8garkJ5IWQ

  • 发表于 2022-10-19 16:43
  • 阅读 ( 228 )
  • 学分 ( 0 )
  • 分类:DeFi

评论