如何构建一个以太坊IPFSReact.js去中心化应用DApp

Posted 汇智网

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何构建一个以太坊IPFSReact.js去中心化应用DApp相关的知识,希望对你有一定的参考价值。

我们为什么要构建这个?在以太坊区块链上存储大量数据是非常昂贵的。根据以太坊的黄皮书,它是大约20,0000gas,256bit/8字节(1字)。基于02/28/2018 gas价格为4gwei/gas。请参阅:https://ethgasstation.info了解当前价格。

每个交易8个字节20,000gas*4gwei/gas=80,000gwei

8,000字节80,000gwei*1000bytes/8=10,000,000gwei/kB=0.01`以太。

0.01以太/kB*1000kB=10以太存储1Mb,价格为860美元/以太=8600.00美元!在以太坊区块链上存储1GB文件需要花费8,600,000.00美元!

存储以太坊的38页PDF黄皮书(520Kb)=4472美元。请参阅: http://eth-converter.com/进行转换计算。

如果我们只能在区块链上存储几Kb的数据,那么我们仍然需要依靠集中式服务器来存储数据。值得庆幸的是,可以使用称为InterPlanetary files system 星际文件系统IPFS的去中心化网络上存储数据的解决方案。请参阅:https://ipfs.io/了解更多信息。在IPFS中查找文件时,你要求网络查找将内容存储在唯一哈希后面的节点。来自IPFS自己的网站:

“IPFS和Blockchain完美匹配!你可以使用IPFS处理大量数据,并将不可变的永久IPFS链接放入区块链交易中。这个时间戳和保护你的内容,而不必将数据放在链本身上。“

我们构建什么?

一个简单的DApp,用于将文档上载到IPFS,然后将IPFS哈希存储在以太坊区块链上。一旦IPFS哈希号被发送到以太坊区块链,用户将收到交易收据。我们将使用Create-React-App框架来构建前端。此Dapp适用于在浏览器中安装了MetaMask的任何用户。

这就是我们完成后DApp的样子:

如何建立它:

注意:如果你只是想要代码,请参阅我的github。

在我们开始之前,这些是我做出的假设:

  • 关于用户的假设:用户安装了Metamask以与DApp交互。

  • 关于你/开发人员的假设:你对javascript、React.js以及Node.js/NPM有一定的了解。重要说明:请确保你运行当前版本的Node和NPM。对于本教程,我正在运行:node v8.9.4和NPM 5.6.0。

  • 安装MetaMask。如果尚未安装MetaMask,请访问https://metamask.io/并按照说明操作。此DApp将假定用户已安装MetaMask。

  • 创建一个目录来存储我们的DApp。对于本教程,我将其称为eth-ipfs

  • 使用NPM安装Create-React-App和其他依赖项。使用NPM并安装以下内容:

npm i create-react-app
npm install react-bootstrap
npm install fs-extra
npm install ipfs-api
npm install web3@^1.0.0-beta.26

输入eth-ipfs目录,键入npm start ,Create-React-App应自动在http://localhost:3000/上呈现。

注意:如果你到目前为止尚未使用create-react-app,则可能必须先在全局安装它:

  • sudo npm install -g create-react-app或者npm install -g create-react-app

  • create-react-app eth-ipfs

  • cd进入eth-ipfs然后运行npm start


在Rinkeby testnet上使用Remix部署以下Solidity代码。请参阅https://remix.ethereum.org。你需要一些Rinkeby测试以太,如果你还没有Rinkeby faucet的一些免费测试以太话。https://www.rinkeby.io/#faucet。

pragma solidity ^0.4.17;
contract Contract {
 string ipfsHash;
 
 function sendHash(string x) public {
   ipfsHash = x;
 }

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

单击“Compile”选项卡,然后单击灰色的“Details”按钮。

如何构建一个以太坊、IPFS、React.js去中心化应用DApp

这将打开“Details”窗口。复制“ABI”,它是一个JSON文件。

如何构建一个以太坊、IPFS、React.js去中心化应用DApp

在我们的“eth-ipfs/src”目录中,创建以下文件: web3.jsipfs.jsstorehash.js。我们的大部分代码都在App.js中。

如何构建一个以太坊、IPFS、React.js去中心化应用DApp

web3.js

我们想使用1.0版本的web3.js,因为与0.20版本不同,1.0允许我们在我们的javascript中使用async并等待而不是promises。目前,MetaMask的默认web3.js提供程序是0.20版本。所以,让我们确保我们覆盖Metamask的web3版本0.20的默认版本,并使用我们的1.0。这是代码:

//为我们的1.0版本覆盖metamask v0.2。 
//1.0让我们使用async和await而不是promises 
import Web3 from ‘web3’;

const web3 = new Web3(window.web3.currentProvider);
export default web3;

storehash.js

import web3 from './web3';
//access our local copy to contract deployed on rinkeby testnet
//use your own contract address
const address = '0xb84b12e953f5bcf01b05f926728e855f2d4a67a9';
//use the ABI from your contract
const abi = [
  {
    "constant": true,
    "inputs": [],
    "name": "getHash",
    "outputs": [
      {
        "name": "x",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "x",
        "type": "string"
      }
    ],
    "name": "sendHash",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  }
]
export default new web3.eth.Contract(abi, address);

ipfs.js

在本教程中,我们将运行ipfs.infura.io节点以连接到IPFS,而不是在我们自己的计算机上运行IPFS守护程序。在代码注释中,如果将IPFS安装为全局依赖项,则还可以选择运行自己的IPFS守护程序。有关使用其节点的更多信息,请参阅https://infura.io/。这是代码:

//using the infura.io node, otherwise ipfs requires you to run a //daemon on your own computer/server.
const IPFS = require(‘ipfs-api’);
const ipfs = new IPFS({ host: ‘ipfs.infura.io’, port: 5001, protocol: ‘https’ });
//run with local daemon
// const ipfsApi = require(‘ipfs-api’);
// const ipfs = new ipfsApi(‘localhost’, ‘5001’, {protocol:‘http’});
export default ipfs;

App.js

这是App.js中的操作顺序:

  • 1.设置状态变量。

  • 2.捕获用户的文件。

  • 3.将文件转换为缓冲区。

  • 4.将缓冲的文件发送到IPFS。

  • 5.IPFS返回一个哈希值。

  • 7.发送IPFS以便在以太坊上存储。

  • 8.使用MetaMask,用户将确认交易到以太坊。

  • 9.以太坊合约将返回一个交易哈希数。

  • 10.交易哈希值可用于生成具有诸如所使用的gas量和块编号之类的信息的交易收据。

  • 11.IPFS和以太坊信息将在使用Bootstrap for CSS的表中呈现。注意:我没有创建一个isLoading类型变量来自动重新呈现blockNumber和gasUsed变量的状态。因此,现在,你必须再次单击或实现自己的加载图标。 描述变量和函数的表,后面是代码本身如下:

如何构建一个以太坊、IPFS、React.js去中心化应用DApp

如何构建一个以太坊、IPFS、React.js去中心化应用DApp

最后,这是App.js代码:

import React, { Component } from ‘react’;
//import logo from ‘./logo.svg’;
import ‘./App.css’;
import web3 from ‘./web3’;
import ipfs from ‘./ipfs’;
import storehash from ‘./storehash’;
class App extends Component {
 
    state = {
      ipfsHash:null,
      buffer:'',
      ethAddress:'',
      blockNumber:'',
      transactionHash:'',
      gasUsed:'',
      txReceipt: ''   
    };
captureFile =(event) => {
        event.stopPropagation()
        event.preventDefault()
        const file = event.target.files[0]
        let reader = new window.FileReader()
        reader.readAsArrayBuffer(file)
        reader.onloadend = () => this.convertToBuffer(reader)    
      };
 convertToBuffer = async(reader) => {
      //file is converted to a buffer for upload to IPFS
        const buffer = await Buffer.from(reader.result);
      //set this buffer -using es6 syntax
        this.setState({buffer});
    };
onClick = async () => {
try{
        this.setState({blockNumber:"waiting.."});
        this.setState({gasUsed:"waiting..."});
//get Transaction Receipt in console on click
//See: https://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransactionreceipt
await web3.eth.getTransactionReceipt(this.state.transactionHash, (err, txReceipt)=>{
          console.log(err,txReceipt);
          this.setState({txReceipt});
        }); //await for getTransactionReceipt
await this.setState({blockNumber: this.state.txReceipt.blockNumber});
        await this.setState({gasUsed: this.state.txReceipt.gasUsed});    
      } //try
    catch(error){
        console.log(error);
      } //catch
  } //onClick
onSubmit = async (event) => {
      event.preventDefault();
     //bring in user's metamask account address
      const accounts = await web3.eth.getAccounts();
     
      console.log('Sending from Metamask account: ' + accounts[0]);
    //obtain contract address from storehash.js
      const ethAddress= await storehash.options.address;
      this.setState({ethAddress});
    //save document to IPFS,return its hash#, and set hash# to state
    //https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#add 
      await ipfs.add(this.state.buffer, (err, ipfsHash) => {
        console.log(err,ipfsHash);
        //setState by setting ipfsHash to ipfsHash[0].hash 
        this.setState({ ipfsHash:ipfsHash[0].hash });
   // call Ethereum contract method "sendHash" and .send IPFS hash to etheruem contract 
  //return the transaction hash from the ethereum contract
 //see, this https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-send
        
        storehash.methods.sendHash(this.state.ipfsHash).send({
          from: accounts[0] 
        }, (error, transactionHash) => {
          console.log(transactionHash);
          this.setState({transactionHash});
        }); //storehash 
      }) //await ipfs.add 
    }; //onSubmit
render() {
      
      return (
        <div className="App">
          <header className="App-header">
            <h1> Ethereum and IPFS with Create React App</h1>
          </header>
          
          <hr />
<Grid>
          <h3> Choose file to send to IPFS </h3>
          <Form onSubmit={this.onSubmit}>
            <input 
              type = "file"
              onChange = {this.captureFile}
            />
             <Button 
             bsStyle="primary" 
             type="submit"> 
             Send it 
             </Button>
          </Form>
<hr/>
 <Button onClick = {this.onClick}> Get Transaction Receipt </Button>
  <Table bordered responsive>
                <thead>
                  <tr>
                    <th>Tx Receipt Category</th>
                    <th>Values</th>
                  </tr>
                </thead>
               
                <tbody>
                  <tr>
                    <td>IPFS Hash # stored on Eth Contract</td>
                    <td>{this.state.ipfsHash}</td>
                  </tr>
                  <tr>
                    <td>Ethereum Contract Address</td>
                    <td>{this.state.ethAddress}</td>
                  </tr>
                  <tr>
                    <td>Tx Hash # </td>
                    <td>{this.state.transactionHash}</td>
                  </tr>
                  <tr>
                    <td>Block Number # </td>
                    <td>{this.state.blockNumber}</td>
                  </tr>
                  <tr>
                    <td>Gas Used</td>
                    <td>{this.state.gasUsed}</td>
                  </tr>
                
                </tbody>
            </Table>
        </Grid>
     </div>
      );
    } //render
} //App
export default App;

我在src/App.css中添加了一些CSS,使它看起来更容易一些:

/*some css I added*/
input[type=”file”] {
 display: inline-block;
}
.table {
 max-width: 90%;
 margin: 10px;
}
.table th {
 text-align: center;
}
/*end of my css*/

并向src/index.js添加一些导入:

/*https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-a-stylesheet*/
import ‘bootstrap/dist/css/bootstrap.css’;
import ‘bootstrap/dist/css/bootstrap-theme.css’;

这就对了!你的DApp应该完成。所以你需要做的就是选择一个文件,发送它,并获得一个交易收据。如果你通过localhost:3000连接到IPFS节点,那么你应该能够在其中一个IPFS网关上看到你的文件。https://gateway.ipfs.io/ipfs/+你的IPFS哈希。

例如:

https://gateway.ipfs.io/ipfs/QmYjh5NsDc6LwU3394NbB42WpQbGVsueVSBmod5WACvpte

关于IPFS的一个注意事项是,除非你的文件被另一个节点接收或者你将其固定,否则IPFS最终将垃圾收集你的文件。他们的网站上有很多关于此的内容。

文章来自官方博客:

http://blog.hubwiz.com。您也可以直接点击左下角的“阅读原文”进行访问。

已经覆盖以下编程技术,发送相应的文字会获取对应教程的信息:

区块链以太坊EOS比特币Tendermint、Node.jsMongoDB、JavaScript、C、C#、php、Python、AngularjsIonic、React、UML、redis、mysqlnginx、CSS、HTML、Bootstrap、Flask、Gulp、Mocha、Git、Meteor、Canvas、zebra、Typescript、Material Design Lite、ECMAScript、Elasticsearch、Mongoose、jQuery、d3.js、django、cheerioSVG、phoneGap、jQueryMobile、Saas、YAML、Vue.js、webpack、Firebird、jQuery Easy UI、ruby、asp.net、c++、Express......

以上是关于如何构建一个以太坊IPFSReact.js去中心化应用DApp的主要内容,如果未能解决你的问题,请参考以下文章

以太坊开发完整去中心化应用 —— 区块链投票系统

以太坊开发DApp实战教程——用区块链星际文件系统(IPFS)Node.js和MongoDB来构建电商平台

Helios——a16z crypto构建的去中心化以太坊轻节点

刘文彬探路以太坊

以太坊代币合约详析

如何使 uniswap v2 去中心化交易所支持以太坊私链