Dapps

創建一個簡單的 DApp

  • December 8, 2018

我想實現"Decentrilized Gallery",並將其實現到區塊鏈(乙太坊),它有點像:

基本的 html 頁面,中間有一個按鈕,可以從本地電腦中選擇一張圖片,之後該圖片將在

IPFS 上“直播”。我知道如何做到這一點,使用 URL

連結作為圖片來源(有很多關於它的教程),但我想嘗試

從本地主機和通過 UI(我的按鈕)而不是通過網頁控制台上傳(教程做)。

誰能告訴我,我應該採取哪些基本步驟,或者指導我朝著正確的方向前進。或者至少,是否有可能或製造scence,會聽取任何建議和批評))

<!doctype>
<html>

<div class="upload">   
    <input type="file" class="file-input">    
   <input type="button" value="Browse">    
   <span class="filename">No file selected</span>  
 </div>

<head>

   <link rel="stylesheet" type="text/css" href="storage/web.css">
   <script type="text/javascript" src="./ipfs/ipfs.js"></script>
   <script type="text/javascript" src="./web3/web3.min.js"></script>
   <script type="text/javascript">

   /* Configuration variables */
   var ipfsHost    = 'localhost';
   var ipfsAPIPort = '5001';
   var ipfsWebPort = '8080';
   var web3Host    = 'http://localhost';
   var web3Port    = '8545';

   /* IPFS initialization */
   var ipfs = window.IpfsApi(ipfsHost, ipfsAPIPort)
   ipfs.swarm.peers(function (err, res) {
       if (err) {
           console.error(err);
       } else {
           var numPeers = res.Peers === null ? 0 : res.Peers.length;
           console.log("IPFS - connected to " + numPeers + " peers");
       }
   });

   /* web3 initialization */
   var Web3 = require('web3');
   var web3 = new Web3();
   web3.setProvider(new web3.providers.HttpProvider(web3Host + ':' + web3Port));
   if (!web3.isConnected()) {
       console.error("Ethereum - no connection to RPC server");
   } else {
       console.log("Ethereum - connected to RPC server");
   }

   /* JavaScript smart contract interface */
   var contractInterface = [{
       "constant": false,
       "inputs": [{
           "name": "x",
           "type": "string"
       }],
       "name": "set",
       "outputs": [],
       "type": "function"
   }, {
       "constant": true,
       "inputs": [],
       "name": "get",
       "outputs": [{
           "name": "x",
           "type": "string"
       }],
       "type": "function"
   }];

   var account = web3.eth.accounts[0];

   var contractObject = {
       from: account,
       gas: 300000,
       data: '0x6060604052610282806100126000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480634ed3885e146100445780636d4ce63c1461009a57610042565b005b6100986004808035906020019082018035906020019191908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050909091905050610115565b005b6100a760048050506101c6565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156101075780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061016457805160ff1916838001178555610195565b82800160010185558215610195579182015b82811115610194578251826000505591602001919060010190610176565b5b5090506101c091906101a2565b808211156101bc57600081815060009055506001016101a2565b5090565b50505b50565b602060405190810160405280600081526020015060006000508054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102735780601f1061024857610100808354040283529160200191610273565b820191906000526020600020905b81548152906001019060200180831161025657829003601f168201915b5050505050905061027f565b9056'
   };

   var sendDataObject = {
       from: account,
       gas: 300000,
   };

   window.ipfs = ipfs;
   window.web3 = web3;
   window.account = account;
   window.contractObject = contractObject;
   window.contract = web3.eth.contract(contractInterface);
   window.ipfsAddress = "http://" + ipfsHost + ':' + ipfsWebPort + "/ipfs";

   function deployStorage() {
       window.IPFSHash = null;
       window.currentData = null;

       if (window.contractInstance) {
           console.error('Contract already been deployed at: ', window.contractAddress);
           return;
       }

       window.contract.new(window.contractObject, function (err, contract) {
           if (err) {
               console.error("Contract deployment error: ", err);
           } else if (contract.address) {
               window.contractAddress = contract.address;
               window.contractInstance = window.contract.at(contract.address);
               console.log("Contract successfully deployed at: ", contract.address);
           } else if (contract.transactionHash) {
               console.log("Awaiting contract deployment with transaction hash: ", contract.transactionHash);
           } else {
               console.error("Unresolved contract deployment error");
           }
       });
   }

   function storeContent(url) {
       window.ipfs.add(url, function(err, result) {
           if (err) {
               console.error("Content submission error:", err);
               return false;
           } else if (result && result[0] && result[0].Hash) {
               console.log("Content successfully stored. IPFS address:", result[0].Hash);
           } else {
               console.error("Unresolved content submission error");
               return null;
           }
       });
   }

   function storeAddress(data) {
       if (!window.contractInstance) {
           console.error('Ensure the storage contract has been deployed');
           return;
       }

       if (window.currentData == data) {
           console.error("Overriding existing data with same data");
           return;
       }

       window.contractInstance.set.sendTransaction(data, window.sendDataObject, function (err, result) {
           if (err) {
               console.error("Transaction submission error:", err);
           } else {
               window.currentData = data;
               console.log("Address successfully stored. Transaction hash:", result);
           }
       });
   }

   function fetchContent() {
       if (!window.contractInstance) {
           console.error("Storage contract has not been deployed");
           return;
       }

       window.contractInstance.get.call(function (err, result) {
           if (err) {
               console.error("Content fetch error:", err);
           } else if (result && window.IPFSHash == result) {
               console.log("New data is not mined yet. Current data: ", result);
               return;
           } else if (result) {
               window.IPFSHash = result;
               var URL = window.ipfsAddress + "/" + result;
               console.log("Content successfully retrieved. IPFS address", result);
               console.log("Content URL:", URL);
           } else {
               console.error('No data, verify the transaction has been mined');
           }
       });
   }

   function getBalance() {
       window.web3.eth.getBalance(window.account, function (err, balance) {
           console.log(parseFloat(window.web3.fromWei(balance, "ether")));
       });
   }

   </script>
</head>

好吧,首先我建構了一些包含IPFS圖像上傳組件的dapp,一般來說概念很簡單。

您需要做的就是創建一個相對簡單的智能合約來儲存 ipfs 雜湊(唯一標識符)。您可以通過https://gateway.ipfs.io/ipfs/IPFSHASH訪問該圖像。看來您使用 javascript 界面的想法是正確的,但我認為您需要一個完整的 dapp。建議使用毛毛雨盒作為起點..

pragma solidity ^0.4.17;
contract Contract {
string ipfsHash;
mapping (address => string[]) userToFiles;
event (string ipfsHash, address owner) filesUploaded;

function setHash(string x) public {
  ipfsHash = x;
  // update files 
  // update array
}

function getHash() public view returns (string x) {
  return ipfsHash;
}
}

當然,在您的情況下,如果不是返回的圖像的一部分,您將需要某種方式來查看所有圖像。

免責聲明這是我自己建構的智能合約,我不保證安全性或其他任何內容,這在solidity V0.5.0中也不起作用。

pragma solidity ^0.4.24;
/// @author David Li
/// @notice Stores a filelist on solidity, since an array of structs cannot easily be returned
/// the structs must be decomposed on the front-end
/// @dev simple filelist contains ipfshash, filename, owner, tags and unix timestamp
/// @dev one way to create a "trello" like application would require creating more modifiers and perhaps
/// role based access control.
/// @dev since I can't use an bytes32 array in solidity, I decided to have tag numbers
/// corresponding to string names, almost like a dictionary look up.
contract FileList {

  /// @dev struct that contains unique link to image (via IPFS), serial Id, and timestamp
  struct File {
     uint256 id;
     string ipfshash;
     bytes32 filename;
     bytes32[5] tags;
     address owner;
     uint256 timestamp;
  }
  uint256 public constant maxAmountOfFiles = 1000;
  // Owner => files
  mapping(address => File[maxAmountOfFiles]) public files;
  // Owner => last files id
  mapping(address => uint256) public lastIds;
  // consider mapping hash to set of tags

  /// @dev main event for smart contract, needed for drizzle to update list of files
  event fileAdded (uint256 fileid, string ipfshash, bytes32 _filename);
  event tagsAdded (bytes32[5] tags);

  /// @dev Add a file to the list
  /// @param ipfshash an ipfshash returned after an image is finished uploaded
  /// @param _filename name of file as a bytes32 as filenames should be short
  /// @param tags array of bytes32 used for sorting/searching files (e,g. blockchain, school, textbook)
  /// @notice updates mappings todos and lastIds
  function addFile(string ipfshash, bytes32 _filename, bytes32[5] tags) public {

     File memory myFile = File(lastIds[msg.sender], ipfshash, _filename, tags,  msg.sender, now);
     // explicitly store tags
     myFile.tags = tags;
     emit tagsAdded (myFile.tags);
     // store new file in mapping

     files[msg.sender][lastIds[msg.sender]] = myFile;
     // emit event, also need for drizzle
     emit fileAdded(lastIds[msg.sender],ipfshash,_filename);
     if(lastIds[msg.sender] >= maxAmountOfFiles) lastIds[msg.sender] = 0;
     else lastIds[msg.sender]++;
  }

  /// @dev return the tags for a specific file 
  /// @param owner --- address of person who uploaded the file 
  /// @param _index --- the file desired, (first file uploaded, second , etc ...)
  function getFileTags(address owner, uint256 _index) external view returns (bytes32[5]) {
      return files[owner][_index].tags;
 }

}

我使用一些鍊式承諾鍊式承諾載入數據。

我記得在IPFS 和 React發布一周後學習了這個教程

例如,您可以看到我建構的一個簡單的 dapp,Ipfs-Dapp ,用於在區塊鏈上儲存圖像。

引用自:https://ethereum.stackexchange.com/questions/63759