【问题标题】:How to store IPFS hash on Ethereum blockchain using smart contracts?如何使用智能合约在以太坊区块链上存储 IPFS 哈希?
【发布时间】:2021-06-29 19:35:00
【问题描述】:

我正在开发一个 react + IPFS DAPP 并制作一个简单的宠物店应用程序。现在我刚刚在 remix 上创建智能合约并尝试它的功能正常工作,但我遇到了一个问题。

交易到 PetShop.generatePet 错误:错误编码参数:错误:无效的数组化值(argument="value", value="QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz", code=INVALID_ARGUMENT, version=bytes/5.0.5)

每当我调用 generatePet 函数并传递 IPFS 哈希时,它都会返回上述错误。

签约宠物店

pragma solidity ^0.6.6;

import "https://github.com/MuhammadSajid404/ERC721-Token/blob/master/ERC721.sol";

contract PetShop is ERC721 {
    
      uint256 public tokenId;
      uint256 public prevOwnerTokenID;
      
      mapping(uint256 => uint256) public priceMapping;
      mapping(uint256 => bytes32) tokenIdToOffchainContentHash;
      
      event PetGenerated(address, uint256, uint256, bytes32);
      event BuyPet(uint256, address, address);
      event SuccessfulEtherWithdrawal(uint256, address, bool);
      
       constructor() public
        ERC721("ShanBuilders", "SBRS")
        {}
     
       function generatePet(uint256 _petPrice, bytes32 contentHash) public returns(bool) {
         
         require(msg.sender != address(0), "Please! Check back! Registeration should not be from zero address");
         require(msg.sender == ownerA, "Only contract owner can generate more pets");
         
         tokenId++;
         require(tokenId <= 16, "More than 16 pets is not allowed");
         
         priceMapping[tokenId] = _petPrice;
         tokenIdToOffchainContentHash[tokenId] = contentHash;
         _mint(ownerA, tokenId);
         emit PetGenerated(ownerA, tokenId, _petPrice, contentHash);
         return true;
       }
       
       function checkPrice(uint256 _tokenId) public view returns(uint256) {
           return priceMapping[_tokenId];
       }
       
       function checkHashForAToken(uint256 _tokenId) public view returns(bytes32) {
           return tokenIdToOffchainContentHash[_tokenId];
       }
       
       function buyPet(uint256 _tokenId) public payable returns(bool, string memory) {
           
           prevOwnerTokenID = _tokenId;
           address buyer = msg.sender;
           address _owner = ownerOf(prevOwnerTokenID);
           
           require(buyer != address(0), "Should not be zero address");
           require(_exists(prevOwnerTokenID), "Invalid property Id, not registered");
           require(msg.value == checkPrice(prevOwnerTokenID), "Please Send The Required Value");
           
           withDraw(msg.value);
            _transfer(_owner, buyer, prevOwnerTokenID);
           emit BuyPet(_tokenId, _owner, buyer);
           return (true, "Succesful");
       }
       
       function withDraw(uint256 _amount) public returns(bool) {
       
        address _owner = ownerOf(prevOwnerTokenID);
        require(_amount > 0, "Amount must be valid");
        
        payable(_owner).transfer(_amount);
        emit SuccessfulEtherWithdrawal(_amount, _owner, true);
        return true;
    }
     
}

注意:我更喜欢使用字节而不是字符串,因为它们比字符串消耗更少的气体。如何解决这个问题,我在 stackoverflow 上看到了很多答案,但实际上我没有得到了解其中任何一个。

【问题讨论】:

    标签: ethereum solidity ipfs


    【解决方案1】:

    bytes32 仅适用于 SHA-256 哈希,对于其他哈希函数或可变长度多哈希格式可能不够。

    https://ethereum.stackexchange.com/questions/6861/what-datatype-should-i-use-for-an-ipfs-address-hash

    【讨论】:

      【解决方案2】:

      使用 sha3-224 将使 IPFS CID 足够短,可以将其存储在 bytes32 中。示例:

      1. 将文件添加到 IPFS 并使用 sha3-224

        $ ipfs add --cid-version=1 --hash=sha3-224 <file>
        bafybohbdfanrni6fre2bmjeivvwqhhpwq3wkqbxsd25az26qgsda
        
      2. CID 转换为 base16

        $ ipfs cid format -b base16 bafybohbdfanrni6fre2bmjeivvwqhhpwq3wkqbxsd25az26qgsda
        f0170171c23281b16a3c58934162488ad6d039df686eca806f21eba0cebd03486
        
      3. 移除 multibase 前缀。它是 CID(在版本 1 中)的第一个字符,对于 base16 编码它是 f。见multibase table on GitHub

        0170171c23281b16a3c58934162488ad6d039df686eca806f21eba0cebd03486

      4. 在实体中

        bytes32 ipfs_cid = 0x0170171c23281b16a3c58934162488ad6d039df686eca806f21eba0cebd03486
        

      或者,如果您有 CIDv0 (Qm...),您可以将其转换为 CIDv1 并拆分为 32 位长前缀(不包括multibase 前缀)和一个 256 位长的哈希并将它们分开存储。

      $ ipfs cid base32 QmccqhJg5wm5kNjAP4k4HrYxoqaXUGNuotDUqfvYBx8jrR # Convert CIDv0 to CIDv1
      bafybeiguffkqavstb6lvfkay5ebplabvc73smdwqiwwxouv4zaupv3vbei
      $ ipfs cid format -b base16 bafybeiguffkqavstb6lvfkay5ebplabvc73smdwqiwwxouv4zaupv3vbei # Convert from base32 (default) to base16 
      f01701220d429550056530f9752a818e902f5803517f7260ed045ad7752bcc828faeea122
      
      bytes4 ipfs_cid_prefix = 0x01701220
      bytes32 ipfs_cid_hash = 0xd429550056530f9752a818e902f5803517f7260ed045ad7752bcc828faeea122
      

      注意:在您的应用程序中对合同中的 CID 进行编码时,不要忘记根据GitHub 上的表格。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-17
        • 2019-04-07
        • 2017-06-24
        • 1970-01-01
        • 2016-12-22
        • 2020-12-07
        • 2023-03-21
        • 1970-01-01
        相关资源
        最近更新 更多