【问题标题】:Create Solidity contract instance as a result of long running process由于长时间运行的过程而创建 Solidity 合约实例
【发布时间】:2022-06-15 23:20:35
【问题描述】:

在一个未确定的、耗时的执行结果后如何写入区块链?

情况:

  1. Web 客户端 (NextJS):用户请求一个长时间运行的进程,最多可能需要 1 小时才能完成。作为这个交易的结果,一个新的合约实例应该被写入区块链。我们不能指望客户端坚持等待 => 使用 NodeJS 或云函数来委派长时间运行的任务。客户端上的 Metamask 将定义合约所有者。
  2. 计划使用 NextJS 路由到 Moralis Cloud Fx 以启动长期运行的任务。这项长期运行任务的结果将是存储到区块链的数字内容。

限制/问题:

  1. 不能让用户等待进程完成
  2. Metamask 在客户端运行
  3. 需要 Moralis Cloud Fx 或 NodeJS 才能访问所有者,以便在未确定的未来时间点实例化合约。

发件人:sequencediagram.org

title Long Running Task to Blockchain
actor User

User->UI:User Request
UI->NodeServer: Delegate Slow Tasks
activate NodeServer
NodeServer->RestService: Start slow process
activate RestService

RestService-->NodeServer: Confirmation ID
NodeServer-->UI: Confirmation ID
UI->Blockchain: Create empty contract

RestService->NodeServer: Result = Data for blockchain
deactivate RestService

NodeServer->Blockchain: **Public?** Contract.setRestResult(Result)

deactivate NodeServer

这就是我计划如何设置跨越客户端和服务器的合同。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;


import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";


contract EncryptionNFT is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private tokenCounter;

    uint256 public fee_wei;
    bool public isLocked;               // has a user paid to access the resource?
    string private confirmationId;      // long temporary password
    string private sensitiveData;       // data produced by long running process
    address public encryptionService;   // service responsible for producing the sensitive data
    address public licensor;            // licensed process
    uint256 public tokenID;             // distinct contract id

    bool private isMutexed = false;             // Reentrancy guard
    bool private isSensitiveDataSet = false;    // Asserts can only be set 1 time

    event unlockPaid(address receiver, uint256 amount);
    event withdrawlMade(address receiver, uint256 amount);

    constructor(string memory name, uint256 _fee_gwei, string memory _confirmationId, address _encryption_service, address _licensor)
        ERC721(name, "DataX")
    {
        fee_wei = _fee_gwei * 1000000000;           // assert numbers are in WEI
        isLocked = true;                            // lock contract by default since data not available => owner shouldn't have to pay unless successful
        confirmationId = _confirmationId;           // assign temporary password
        encryptionService = _encryption_service;    // assign addresses for payments
        licensor = _licensor;                       // assign addresses for payments

        tokenID = tokenCounter.current();           // Set/Mint with distinct token id
        _safeMint(msg.sender, tokenID);
        tokenCounter.increment();
    }

    function unlock() public payable {
        require(isLocked == true, "Contract already unlocked.");
        require(msg.value >= fee_wei, "Not enough WEI to unlock NFT.");
        require(isMutexed == false, "Reentrant call detected!");
        isMutexed = true;

        // DO PAYMENTS
        uint256 rcv_payment = msg.value;
        uint256 licensor_cut = rcv_payment / 10;
        uint256 encryptor_cut = rcv_payment - licensor_cut;

        (bool is_encryptor_success, ) = payable(encryptionService).call{value: encryptor_cut}("");
        require(is_encryptor_success, "Encryptor transfer failed.");
        emit unlockPaid(encryptionService, encryptor_cut);

        (bool is_licensor_success, ) = payable(licensor).call{value: licensor_cut}("");
        require(is_licensor_success, "Licensor transfer failed.");
        emit unlockPaid(licensor, licensor_cut);

        isLocked = false;
        isMutexed = false;
    }

    function withdraw() public payable {
        require(msg.sender == ownerOf(tokenID), "Only owner may withdraw.");
        require(isLocked == false, "Contract must be unlocked.");
        require(isMutexed == false, "Reentrant call detected!");
        isMutexed = true;

        // DO PAYMENTS
        uint256 rcv_payment = msg.value;
        uint256 nft_service_cut = rcv_payment / 10;
        uint256 licensor_cut = nft_service_cut / 10;
        uint256 encryptor_cut = rcv_payment - licensor_cut;
        uint256 nft_owner_cut = rcv_payment - nft_service_cut;

        (bool is_encryptor_success, ) = payable(encryptionService).call{value: encryptor_cut}("");
        require(is_encryptor_success, "Encryptor transfer failed.");
        emit withdrawlMade(encryptionService, encryptor_cut);

        (bool is_licensor_success, ) = payable(licensor).call{value: licensor_cut}("");
        require(is_licensor_success, "Licensor transfer failed.");
        emit withdrawlMade(licensor, licensor_cut);

        (bool is_nft_owner_success, ) = payable(ownerOf(tokenID)).call{value: nft_owner_cut}("");
        require(is_nft_owner_success, "NFT Owner transfer failed.");
        emit withdrawlMade(ownerOf(tokenID), nft_owner_cut);

        isMutexed = false;
  }

    function setTokenURI(string memory _tokenURI) public {
        require(_isApprovedOrOwner(_msgSender(), tokenID), "ERC721: transfer caller is not owner nor approved.");
        _setTokenURI(tokenID, _tokenURI);
    }

    // Here's how I was planning to allow a server-side process to set the data on REST service completion (slow task)
    function setSensitiveData(string memory _confirmationId, string memory _sensitiveData) public {
        require(keccak256(bytes(_confirmationId)) == keccak256(bytes(confirmationId)), "Confirmation ID does not match.");
        require(isSensitiveDataSet == false, "Sensitive Data has already been set");
        sensitiveData = _sensitiveData;
        isSensitiveDataSet = true;
    }

    function getSensitiveData() public view returns (string memory){
        require(isSensitiveDataSet == true, "Sensitive Data must be set first.");
        require(msg.sender == encryptionService, "Only encryption service accessible.");
        return sensitiveData;
    }
}

编辑我刚刚发现 Moralis 有一个会话,似乎允许作为相应用户进行服务器端访问。以前有人玩过这个吗?它适用于这个用例吗?

Moralis Docs

【问题讨论】:

标签: javascript blockchain solidity


猜你喜欢
  • 1970-01-01
  • 2022-07-05
  • 2017-08-19
  • 2018-09-05
  • 1970-01-01
  • 2018-04-13
  • 1970-01-01
  • 1970-01-01
  • 2019-03-29
相关资源
最近更新 更多