WHY ARE WE BUILDING THIS?

It is prohibitively expensive to store a lot of data on the Ethereum blockchain. According to Ethereum’s yellow paper it is approximately 20,0000 gas for 256bit/8 bytes (1word). Based on 02/28/2018 gas prices of 4 gwei/gas. See: https://ethgasstation.info for current prices.

20,000 gas per Transaction of 8 bytes x 4 gwei/gas = 80,000 gwei for 8 bytes.

80,000 gwei for 8 bytes. x 1000bytes/8 = 10,000,000 gwei/kB = .01 Ether

.01 Ether/kB x 1000kB = 10 Ether to store a 1Mb at $860/ether = $8600.00! It would cost $8,600,000.00 to store a 1 GB file on the Ethereum blockchain!

To store Ethereum’s 38 page PDF yellow paper (520Kb) = $4472 USD. See: http://eth-converter.com/ for conversions.

If we can only afford to store a couple of Kb of data on the blockchain, then we would still have to rely on a centralized server to store data. Thankfully, a solution to store data on decentralized network called the InterPlanetary File System (“IPFS”) is available. See: https://ipfs.io/ to read more. When looking up files in IPFS, you are asking the network to find nodes storing the content behind a unique hash. From IPFS’s own website:

“IPFS and the Blockchain are a perfect match! You can address large amounts of data with IPFS, and place the immutable, permanent IPFS links into a blockchain transaction. This timestamps and secures your content, without having to put the data on the chain itself.”

WHAT ARE WE BUILDING?

A simple DApp to upload a document to IPFS and then store the IPFS hash on the Ethereum blockchain. Once the IPFS hash number is sent to the Ethereum blockchain, the user will receive a transaction receipt. We will use Create-React-App framework to make a front-end. This Dapp works with any user that has MetaMask installed in their browser.

This is what the DApp will look like when we are done:

HOW TO BUILD IT:

NOTE: Please see my github at https://github.com/mcchan1/eth-ipfs if you just want the code.

Before we begin, these are the assumptions I’ve made:

Assumptions about User:The User has Metamask installed to interact with DApp.

Assumptions about you/Developer:You have some familiarity with JavaScript and/or React.js as well as Node.js/NPM. Important note: please make sure you are running a current version of Node and NPM. For this tutorial I’m running: node v8.9.4 and NPM 5.6.0 .

Install MetaMask.If you have do not already have MetaMask installed, please go to https://metamask.io/ and follow the instructions. This DApp will assume the user has MetaMask installed.

Create a directory to store our DApp.For this tutorial, I’ll call it “eth-ipfs.”

Install Create-React-App and other dependencies using NPM.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, type “npm start”and Create-React-App should automatically render on http://localhost:3000/ .

Deploy the following Solidity code using Remix on the Rinkeby testnet.See, https://remix.ethereum.org . You will need some Rinkeby test ether, if you do not already have some go the Rinkeby faucet for free 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 where it is deployed and Application Binary Interface (ABI).To obtain the ABI of the contract, in Remix go to your contract address:

Click the “Compile” tab, then click the grey “Details” button.

This will bring up the Details window. Copy the “ABI,” it is a JSON file.

Personally I prefer put the ABI JSON into a formatter, such as https://jsonformatter.org and check if it is valid before using it in my javascript code. Save the contract address and ABI for later.

Inside our “eth-ipfs/src” directory, create the following files: web3.js , ipfs.js , and storehash.js . The bulk of our code will be in App.js .

web3.js

We want to use the 1.0 version of web3.js , because unlike the 0.20 version, 1.0 allows us to use async and await instead of promises in our javascript. At the moment, MetaMask’s default web3.js provider is version 0.20. So, lets make sure we override the default version of Metamask’s web3 version 0.20, and use our 1.0. Here is the code:

//overrides metamask v0.2 for our 1.0 version.
//1.0 lets us 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 for web3.js to have access to the contract we deployed to Ethereum’s Rinkeby testnet earlier, you will need the following:1) contract address and 2) the ABI from the contract. Be sure to import your web3.js file from your /src directory as well. Here 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 run the ipfs.infura.io node to connect to IPFS instead of running an IPFS daemon on our own computer. In the code comments, you can also choose to run your own IPFS daemon if you install IPFS as a global dependency. See, https://infura.io/ for more information about using their nodes. Here 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 the state variables.
  2. Capture the User’s file.
  3. Convert the file to a buffer.
  4. Send the buffered file to IPFS
  5. IPFS returns a hash.
  6. Get the User’s MetaMask Ethereum address
  7. Send the IPFS for storage on Ethereum.
  8. Using MetaMask, User will confirm the transaction to Ethereum.
  9. Ethereum contract will return a transaction hash number.
  10. The transaction hash number can be used to generate a transaction receipt with information such as the amount of gas used and the block number.
  11. The IPFS and Ethereum information will render as it becomes available in a table using Bootstrap for CSS. NOTE: I didn’t create an isLoading type variable to automatically re-render state for the blockNumber and gasUsed variables. So for now, you will have to click again or implement your own loading icon. A table describing the variables and functions, followed by the code itself are below:

Finally, here 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 IPFSconst buffer = await Buffer.from(reader.result);//set this buffer -using es6 syntaxthis.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});    } //trycatch(error){console.log(error);} //catch} //onClick
onSubmit = async (event) => {event.preventDefault();
//bring in user's metamask account addressconst accounts = await web3.eth.getAccounts();console.log('Sending from Metamask account: ' + accounts[0]);
//obtain contract address from storehash.jsconst 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-sendstorehash.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 a little bit of CSS in src/ App.css to make it a little easier on the eyes:

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

That is it! Your DApp should be done. So all you need to do is a choose a file, send it, and get a transaction receipt. If you are connected to an IPFS node via your localhost:3000, then you should be able to see your file at one of the IPFS gateways. https://gateway.ipfs.io/ipfs/ + your IPFS hash#.

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

A note about IPFS, is that unless your file is picked up by another node or you pin it, IPFS will eventually be garbage collect your file. There is a lot more about this on their website.

Reference links:

  • https://ipfs.io/docs/getting-started/
  • https://web3js.readthedocs.io/en/1.0/index.html
  • https://infura.io/
  • https://react-bootstrap.github.io/getting-started/introduction
  • https://metamask.io/
  • https://github.com/ipfs/js-ipfs-api
  • https://remix.ethereum.org/
  • https://ethereum.github.io/yellowpaper/paper.pdf
  • https://ethgasstation.info
  • http://eth-converter.com/
  • https://www.rinkeby.io/#faucet
  • https://developer.mozilla.org/en-US/docs/Web/API/FileReader
  • https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#add
  • https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-send
  • https://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransactionreceipt
  • https://github.com/mcchan1/eth-ipfs

關鍵詞:IPFS React

相關推薦:

ERC20 Token Development on RSK with OpenZeppelin and Web3.py

Ethereum Development: Getting started

Meet smart-contracts in practice

Blockchain, Part II: Configuring a Blockchain Network and Leveraging the Technology

When blockchain serves human rights: an uplifting use-case

Creating ERC-20 Standard Token

科普 | 小跑進入以太坊,Part-3

The Future of Native Mobile Apps on Blockchain — What They Should Look Like, and How to Bui...

Web3與智能合約交互實戰

Ethereum Smart Contracts in Python: a comprehensive(ish) guide

Build a simple Ethereum + IPFS+ React.js DApp.相关推荐

  1. 如何使用React.js和Heroku快速实现从想法到URL的转变

    by Tom Schweers 由汤姆·史威士(Tom Schweers) 如何使用React.js和Heroku快速实现从想法到URL的转变 (How to go from idea to URL ...

  2. parcel react_如何使用Parcel捆绑React.js应用程序

    parcel react by Michael Ozoemena 迈克尔·奥索埃梅纳(Michael Ozoemena) 如何使用Parcel捆绑React.js应用程序 (How to use Pa ...

  3. 免费的React课程,通过构建聊天应用程序来提高您的React JS技能

    Chat is eating the world, and React is eating front-end development. So what could be better than le ...

  4. react.js app_在React.JS中创建一个Weather App

    react.js app Hello readers! 各位读者好! In this article, you will know how to develop a basic weather app ...

  5. 坚如磐石的React.js基础:入门指南

    by Rajat Saxena 通过拉贾特·萨克森纳(Rajat Saxena) 坚如磐石的React.js基础:入门指南 (Rock Solid React.js Foundations: A Be ...

  6. react 使用 svg_使用SVG和React.js构建日历热图

    react 使用 svg 跳舞语法 (Dancing Syntax) 介绍 (Introduction) In 2016, I had put my academic plans on hold af ...

  7. react.js做小程序_如何使用React.js构建现代的聊天应用程序

    react.js做小程序 In this tutorial, I will guide you to build your own group chat application using React ...

  8. 使用React.js开发自己的Chrome插件

    文章目录 1.配置环境 2.最简项目 3.修改内容 1.配置环境 先安装nodejs,下载地址:下载 | Node.js 然后打开node命令行: 更改更新源: npm config set regi ...

  9. 使用webpack2.0 搭建react.js项目

    最近一段时间没有写react.js,发现webpack已经完全升级为2.0了,升级后导致以前的项目不能正常编译,只能重新实践一番 关于webpack2.0和1.x的区别概括起来就是tree shaki ...

最新文章

  1. Java中的“可运行的实现”与“扩展线程”
  2. 【正一专栏】巴萨和曼城都那么强了还在买人续约
  3. 网传B站数据中心起火?所谓“现场图片”却是盗来的
  4. 求最长上升子序列(Lis模板)
  5. LCD驱动 15-1
  6. three.js mtl材质贴图未显示_C4D材质到底该怎么用?大多数设计师都没搞明白!
  7. Python学生成绩处理专业版
  8. 利用 PIL模块实现生成动态验证码
  9. URLSession实现iTunes搜索听歌
  10. springboot实现数据库读写分离的一款框架
  11. 带视频加密功能的视频播放器
  12. 微信小程序疑难杂症---修改数组里的某个属性的值
  13. C++作业之模拟打牌:小喵钓鱼
  14. 在北京注册科技类公司的经历(一):名称预审
  15. oh-my-zsh详细安装与主题插件配置
  16. 斐波那契数列算法c语言实现
  17. 有符号数与无符号数的除法(转载)
  18. (二)Linux ALSA 音频系统:逻辑设备篇
  19. 湘鄂情欲加码大数据 若定增失败将变卖资产
  20. #ifdef __cplusplus 是什么意思?

热门文章

  1. sort函数用法python_python内置函数sorted()及sort() 函数用法和区别
  2. Netty-1-一个简单的服务器实例
  3. 克鲁斯卡尔算法c语言,Kruskal算法(一)之 C语言详解
  4. python如何导入hotp库_Google Authenticator在Python中的实现
  5. vue跳转静态HTML,Vue-router,在静态切换的世界中翱翔
  6. 攻防世界(Ctf-Web 新手练习区 Writeup)
  7. 学习笔记2—MATLAB的copyfile技巧
  8. 民生证券手机网上开户流程
  9. 数据库设计的三大范式通俗解释
  10. cookie 保存导航菜单的展开状态