IPFS入门实践

 

目录

IPFS安装:

Some things to try (Quick start)

Taking your Node Online

Transfer a file to IPFS

IPFS与DApp开发实战

7.1 安装Truffle unbox react

7.2 安装ipfs-api

7.3 修改智能合约代码

7.4 编译智能合约

7.5 部署智能合约

7.5 修改App.js文件

7.6 新建终端,执行"npm start"命令,

参考

IPFS安装:

$ tar xvfz go-ipfs.tar.gz

$ cd go-ipfs

$ ./install.sh

$ ipfs help

$ ipfs init

$ ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme  

$ ipfs cat /ipfs/<HASH>/quick-start

 

Some things to try (Quick start)

Basic proof of 'ipfs working' locally:

echo "hello world" > hello
ipfs add hello
# This should output a hash string that looks something like:
# QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o
ipfs cat <that hash>

Add a file to ipfs:
$echo "hello world" >hello
$ipfs add hello


View it:
$ipfs cat <the-hash-you-got-here>


Try a directory:
$ mkdir foo
$  mkdir foo/bar
$  echo "baz" > foo/baz
$  echo "baz" > foo/bar/baz
$  ipfs add -r foo


View things:
  ipfs ls <the-hash-here>
  ipfs ls <the-hash-here>/bar
  ipfs cat <the-hash-here>/baz
  ipfs cat <the-hash-here>/bar/baz
  ipfs cat <the-hash-here>/bar
  ipfs ls <the-hash-here>/baz

Get:

  ipfs get <the-hash-here> -o foo2
  diff foo foo2


Objects:

  ipfs object get <the-hash-here>
  ipfs object get <the-hash-here>/foo2
  ipfs object --help


Pin + GC:

  ipfs pin add <the-hash-here>
  ipfs repo gc
  ipfs ls <the-hash-here>
  ipfs pin rm <the-hash-here>
  ipfs repo gc


Daemon:

  ipfs daemon  (in another terminal)
  ipfs id


Network:

  (must be online)
  ipfs swarm peers  // ipfs swarm peers| wc -l
  ipfs id
  ipfs cat <hash-of-remote-object>


Mount:

  (warning: fuse is finicky!)
  ipfs mount
  cd /ipfs/<the-hash-here>
  ls


Tool:

  ipfs version
  ipfs update
  ipfs commands
  ipfs config --help
  open http://localhost:5001/webui


Browse:

  webui:

    http://localhost:5001/webui

 

Taking your Node Online

Once you’re ready to join your node to the public network, run the ipfs daemon in another terminal and wait for all three lines below to appear to know that your node is ready:

> ipfs daemon
Initializing daemon...
API server listening on /ip4/127.0.0.1/tcp/5001
Gateway server listening on /ip4/127.0.0.1/tcp/8080

Make note of the tcp ports you receive. If they are different, use yours in the commands below.

 

Transfer a file to IPFS

# On A
> ipfs add myfile.txt
added QmZJ1xT1T9KYkHhgRhbv8D7mYrbemaXwYUkg7CeHdrk1Ye myfile.txt

# On B
> ipfs get QmZJ1xT1T9KYkHhgRhbv8D7mYrbemaXwYUkg7CeHdrk1Ye
Saving file(s) to QmZJ1xT1T9KYkHhgRhbv8D7mYrbemaXwYUkg7CeHdrk1Ye
 13 B / 13 B [=====================================================] 100.00% 1s

>ipfs ls -v QmZJ1xT1T9KYkHhgRhbv8D7mYrbemaXwYUkg7CeHdrk1Ye

>ipfs block stat: 查询block的数据大小,不包含子块。
>ipfs refs -r:列出所有数据块的子块信息
>ipfs ls or ipfs object links:显示所有的子块和块的大小

实验效果图:

 

 ipfs cat /ipfs/QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg >cat.jpg 

 

QmRVWUfHFkEX8HGwtwau9pvcJ99vWySnQ9TryTQ6gqyJdB

 

  • IPFS与以太坊DApp结合的好处

    在以太坊平台上,往区块链写入数据需要花费以太币,调用智能合约执行每一行代码的时候,都需要一定量的gas交易费。区块链存储大数据成本很高,而且不合理。
    可以先将文件存储到IPFS,然后得到文件的Hash存储到以太坊区块链中。读取文件的时候,从以太坊区块链中获取文件的Hash,再通过Hash来读取IPFS网络上的文件。
    使用官方提供的ipfs-api,可以很方便地在代码中操作节点将数据上传到IPFS,或者通过Hash从IPFS读取数据。
    Truffle框架提供了快速搭建包含以太坊智能合约的React项目,可以通过"truffle unbox react"创建工程,然后安装ipfs-api依赖库。于是,可以在前端方便地调用IPFS的接口来读取、上传文件。

    truffle unbox react官网:
    http://truffleframework.com/boxes/react

IPFS与DApp开发实战

7.1 安装Truffle unbox react

新建一个空目录"ipfs_dapp",然后执行安装命令

truffle unbox react
wenzildeiMac:ipfs_dapp wenzil$ pwd
/Users/wenzil/Desktop/study/ipfs_dapp
wenzildeiMac:ipfs_dapp wenzil$ truffle unbox react
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
  
Commands:
  
  Compile:              truffle compile
  Migrate:              truffle migrate
  Test contracts:       truffle test
  Test dapp:            npm test
  Run dev server:       npm run start
  Build for production: npm run build

7.2 安装ipfs-api

在打开ipfs daemon联网之后,输入以下指令
$cd client   su
#npm install --save ipfs-api 或者  npm install --save ipfs-http-client

 

7.3 修改智能合约代码

修改contracts目录中的"SimpleStorage.sol",修改后完整代码:

pragma solidity ^0.4.18;

contract SimpleStorage {
  // 用于存储图片的哈希值
  string storedData;

  function set(string x) public {
    storedData = x;
  }

  function get() public view returns (string) {
    return storedData;
  }
}    

 

7.5 编译部署智能合约

ipfs-dapp$truffle compile
ipfs-dapp$ truffle migrate --reset
记住address

进入remix-ide,复制SimpleStorage.sol代码,然后切换到"Run"菜单,选择"Injected Web3"进行智能合约的部署

Remix-IDE部署智能合约

Remix-IDE部署智能合约-确认

然后复制智能合约地址,App.js文件中会用到合约地址为:"0xb177d6cf6916f128c9931e610c63208d9c5a40f3"

7.5 修改App.js文件

import React, {Component} from 'react'
import SimpleStorageContract from 
'../build/contracts/SimpleStorage.json'
import getWeb3 from './utils/getWeb3'

import './css/oswald.css'
import './css/open-sans.css'
import './css/pure-min.css'
import './App.css'

const ipfsAPI = require('ipfs-api');
const ipfs = ipfsAPI({
  host: 'localhost',
  port: '5001',
  protocol: 'http'
});

const contract = require('truffle-contract')
const simpleStorage = contract(SimpleStorageContract)
let account;

// Declaring this for later so we can chain functions on SimpleStorage.
let contractInstance;

let saveImageToIPFS = (reader) => {
    return new Promise(function(resolve, reject) {
        const buffer = Buffer.from(reader.result);
        ipfs.add(buffer).then((response) => {
        console.log(response)
        resolve(response[0].hash);
     }).catch((err) => {
        console.error(err)
        reject(err);
     })
  })
}

class App extends Component {
   constructor(props) {
   super(props)

   this.state = {
       blockChainHash: null,
       web3: null,
       address: null,
       imageHash: null,
       isSuccess: false
  }
}

componentWillMount() {
    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");
      console.log(res);
    }
});

getWeb3.then(results => {
    this.setState({web3: results.web3})

    // Instantiate contract once web3 provided.
    this.instantiateContract()
  }).catch(() => {
    console.log('Error finding web3.')
  })
}

instantiateContract = () => {
  simpleStorage.setProvider(this.state.web3.currentProvider);
  this.state.web3.eth.getAccounts((error, accounts) => {
  account = accounts[0];
    simpleStorage.at('0xb177d6cf6916f128c9931e610c63208d9c5a40f3').then((contract) => {
    console.log(contract.address);
    contractInstance = contract;
    this.setState({address: contractInstance.address});
    return;
  });
})

}
render() {
  return (
    <div className="App">
    <div style={{marginTop:10}}>智能合约地址:</div>
    <div>{this.state.address}</div>
    <div style={{marginTop:10}}>上传图片到IPFS:</div>
    <div>
      <label id="file">选择图片</label>
      <input type="file" ref="file" id="file" name="file" multiple="multiple"/>
    </div>
    <button style={{marginTop:10}} onClick={() => {
        var file = this.refs.file.files[0];
        var reader = new FileReader();
        reader.readAsArrayBuffer(file)
        reader.onloadend = function(e) {
          console.log(reader);
          saveImageToIPFS(reader).then((hash) => {
            console.log(hash);
            this.setState({imageHash: hash})
          });
      }.bind(this);
  }}>开始上传</button>

  <div style={{marginTop:10}}>图片哈希值:{this.state.imageHash}</div>
  <button onClick={() => {
       contractInstance.set(this.state.imageHash, {from: account}).then(() => {
          console.log('图片的hash已经写入到区块链!');
          this.setState({isSuccess: true});
      })
  }}>图片哈希写入区块链</button>

  {
    this.state.isSuccess
      ? <div style={{marginTop:10}}>
          <div>图片哈希成功写入区块链!</div>
          <button onClick={() => {
              contractInstance.get({from: account}).then((data) => {
                console.log(data);
                this.setState({blockChainHash: data});
              })
            }}>从区块链读取图片哈希</button>
        </div>
      : <div/>
  }
  {
    this.state.blockChainHash
      ? <div style={{marginTop:10}}>
          <div>从区块链读取到的哈希值:{this.state.blockChainHash}</div>
        </div>
      : <div/>
  }
  {
    this.state.blockChainHash
      ? <div style={{marginTop:10}}>
          <div>访问本地文件:</div>
          <div>{"http://localhost:8082/ipfs/" + this.state.imageHash}</div>
          <div>访问IPFS网关:</div>
          <div>{"https://ipfs.io/ipfs/" + this.state.imageHash}</div>
          <img alt="" style={{width: 100, height: 100 }} src={"https://ipfs.io/ipfs/" + this.state.imageHash}/>
        </div>
      : <img alt=""/>
    }
    </div>);
  }
}

export default App

7.6 新建终端,执行"client$ npm run start"命令,

 

用react github 原始项目example跑的结果,看到这个图实属不易啊

小激动

 

但是我们看到stored value:0是错误的,这是因为部署合约的网络是localhost:8545; 而项目运行时injected web3来自MetaMask;

所以需要MetaMask连接到localhost:8545.

点击右上角猫猫,new network->url: http://127.0.0.1:8545   -> 可以查看/etc/hosts文件中有一行 127.0.0.1   localhost

MetaMask成功连接到本地网后,再运行:

npm run start

会自动打开网页,并且弹出MetaMask;  

然后上传一张本地图片,之后点击"图片哈希写入区块链"按钮

运行结果1

最终效果如图:

运行结果

访问IPFS网关:
https://ipfs.io/ipfs/QmbHptfJfyuGAZxstFYgAVfz33cytR1seTD3ZabBSDd899

发现图片已经成功写入IPFS,如图:

运行结果3

备注:本地IPFS网关端口默认为8080,我的电脑上端口冲突了,系统自动修改为8082。

 

参考

1. https://docs.ipfs.io/introduction/usage/ 

2. IPFS简介和入门实践

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值