Constructing an application dApp of Etherfang+IPFS+React.js

Posted by thepreacher on Wed, 08 May 2019 18:00:02 +0200

Why do we build this? It is very expensive to store a large amount of data on the block chain of Taifang. According to the Yellow Paper of ETF, it is about 20,000 gas, 256 bit/8 bytes (1 word). Based on 02/28/2018 gas price is 4 gwei/gas. Please refer to: https://ethgasstation.info Know the current price.

Each transaction has 8 bytes of 20,000 gas*4 gwei/gas=80,000 gwei.

8,000 bytes 80,000 gwei*1000bytes/8=10,000,000 gwei/kB=0.01`ether.

0.01 ether / kB*1000kB=10 ether storage 1Mb, the price is 860 dollars / ether = 8600.00 dollars! It costs $8,600,000.00 to store 1GB files on the Taifang block chain!

Store 38 pages of PDF Yellow Paper (520Kb) in ETF = $4472. Please refer to: http://eth-converter.com/ Conversion calculation is performed.

If we can only store a few Kb of data on a block chain, then we still need to rely on centralized servers to store data. Fortunately, you can use what is known as `InterPlanetary files'.
system Interstellar File system IPFS `Decentralized Network Storage Data Solution. Please refer to: https://ipfs.io/ Learn more. When searching for files in IPFS, you ask the network to find nodes that store content behind a unique hash. From IPFS's own website:

"IPFS and Blockchain match perfectly! You can use IPFS to process large amounts of data and put immutable permanent IPFS links into block chain transactions. This timestamp protects your content without having to put data on the chain itself. "

What do we build?

A simple DApp for uploading documents to IPFS and storing IPFS hashes on the Ethernet block chain. Once the IPFS hash number is sent to the Ethernet block chain, the user receives the transaction receipt. We will use the Create-React-App framework to build the front end. This Dapp is suitable for any user who has MetaMask installed in the browser.

That's what DApp looks like when we're done:

How to build it:

Note: If you just want code, please refer to mine. github.

Before we begin, these are my assumptions:

  • Assumption about users: Users install Metamask s to interact with DApp.
  • About your / developer assumptions: You have some knowledge of JavaScript, React.js, and Node.js/NPM. Important Note: Make sure you run the current version of Node and NPM. For this tutorial, I am running: node v8.9.4 and NPM 5.6.0.
  • Install MetaMask. If MetaMask has not been installed, visit https://metamask.io/ And follow the instructions. This DApp assumes that the user has MetaMask installed.
  • Create a directory to store our DApp. For this tutorial, I call it eth-ipfs.
  • Use NPM to install Create-React-App and other dependencies. Use NPM and install the following:
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

Enter the eth-ipfs directory and npm start. Create-React-App should be automatically rendered at http://localhost:3000/.

Note: If you haven't used create-react-app so far, you may have to install it globally first.

    1. Sudo NPM install-g create-react-app or NPM install-g create-react-app
    1. create-react-app eth-ipfs
    1. cd enters eth-ipfs and runs npm start

Deploy the following Solidity code on Rinkeby testnet using Remix. see also https://remix.ethereum.org . You need some Rinkeby test ether, if you don't have some free Rinkeby faucet test ether. 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;
 }
}

Save the contract address and application binary interface (ABI) for deploying it. To get the ABI of the contract, please transfer to your contract address in Remix:

Click the Compile tab, and then click the gray Details button.

This opens the Details window. Copy "ABI", which is a JSON file.

I personally prefer to put ABI JSON in a formatter, such as https://jsonformatter.org And check if it works before I use it in my javascript code. Save the contract address and ABI for future use.

In our "eth-ipfs/src" directory, create the following files: web3.js, ipfs.js and storehash.js. Most of our code is in App.js.

web3.js

We want to use version 1.0 of web3.js, because unlike version 0.20, version 1.0 allows us to use async in our javascript and wait instead of promises. Currently, MetaMask's default web3.js provider is version 0.20. So let's make sure we cover the default version of Metamask's Web3 version 0.20 and use our 1.0. This is the code:

//Override metamask v0.2 for our version 1.0. 
//1.0 Let's use async and await instead of promises 
import Web3 from 'web3';

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

storehash.js

In order to enable web3.js to access our previously deployed Linkeby testnet contract in Etherford, you need the following contents: 1) contract address and 2) ABI in the contract. Be sure to import web3.js files from the / src directory. This is the code:

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

In this tutorial, we will runipfs.infura.io Nodes to connect to IPFS, rather than running IPFS daemons on our own computers. In the code comment, if you install IPFS as a global dependency, you can also choose to run your own IPFS daemon. For more information about using its nodes, see https://infura.io/ . This is the code:

//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

This is the order of operations in App.js:

  • 1. Set state variables.
  • 2. Capture user's files.
  • 3. Convert files to buffers.
  • 4. Send buffered files to IPFS.
  • IPFS returns a hash value.
  • 6. Get the user's MetaMask Ethernet address
  • 7. Send IPFS for storage in the Ethernet workshop.
  • 8. Using MetaMask, the user will confirm the transaction to ETF.
  • 9. The ETF contract will return a transaction hash number.
  • 10. The transaction hash value can be used to generate a transaction receipt with information such as gas volume and block number used.
  • 11.IPFS and ETF information will be presented in tables using Bootstrap for CSS. Note: I did not create an isLoading type variable to automatically reproduce the status of blockNumber and gasUsed variables. So now, you have to click or implement your own loading icon again. A table describing variables and functions, followed by the code itself, is as follows:

Finally, this is the App.js code:

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;

I added some CSS to src/App.css to make it look easier:

/*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*/

And add some imports to 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';

That's right! Your DApp should be completed. So all you need to do is select a file, send it, and get a transaction receipt. If you connect to an IPFS node through localhost:3000, you should be able to see your files on one of the IPFS gateways. https://gateway.ipfs.io/ipfs/+your IPFS hash.

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

One thing to note about IPFS is that unless your files are received by another node or fixed by you, IPFS will eventually garbage your files. They have a lot of content on their website.

======================================================================

Share some interactive online programming practical tutorials related to block chains such as ethernet, EOS, Bitcoin, etc.

  • java Ethernet workshop development tutorial It is mainly for java and android programmers to develop block chain etheric workshop web3j in detail.
  • python etheric workshop Mainly for python engineers to use web3.py for block chain Ethernet development in detail.
  • php Ethernet It mainly introduces the use of php for intelligent contract development interaction, account creation, transactions, transfer, token development, filters and transactions.
  • Introductory Course of ETF This paper mainly introduces the development of intelligent contract and dapp application, which is suitable for introduction.
  • Advanced Course of ETF Development It mainly introduces how to use node.js, mongodb, block chain and ipfs to realize the de-centralized e-commerce DApp, which is suitable for advanced stage.
  • C# Ethernet It mainly explains how to use C# to develop Ethernet Application Based on. Net, including account management, status and transaction, intelligent contract development and interaction, filters and transactions.
  • EOS tutorial This course helps you get a quick start on the development of decentralized application of EOS block chain. It covers the core knowledge points of EOS toolchain, account and wallet, issuing tokens, intelligent contract development and deployment, code and intelligent contract interaction, and finally completes the development of a note DApp with all knowledge points.
  • java Bitcoin Development Tutorial This course is for beginners. It covers the core concepts of Bitcoin, such as block chain storage, decentralized consensus mechanism, key and script, transaction and UTXO. It also explains in detail how to integrate Bitcoin support functions in Java code, such as creating addresses, managing wallets, building bare transactions, etc. It is a rare Bitcoin development course for Java engineers. .
  • php Bitcoin Development Tutorial This course is for beginners. It covers the core concepts of Bitcoin, such as block chain storage, decentralized consensus mechanism, key and script, transaction and UTXO. It also explains in detail how to integrate Bitcoin support functions in Php code, such as creating addresses, managing wallets, building bare transactions, etc. It is a rare Bitcoin development course for Php engineers.
  • Detailed description of tendermint block chain development This course is suitable for engineers who want to use tendermint to develop block chains. It includes the core concepts of tendermint application development model, such as ABCI interface, Merkel tree, multi-version state library, and rich practical codes such as token issuance. It is the best choice for go language engineers to develop fast-start block chains.

Huizhi original translation, reprinted please indicate the source. Here is the original text. Constructing a Simple Etaifang+IPFS+React.js DApp

Topics: Database React npm Java PHP