1. 程式人生 > >用web3.js與智慧合約互動

用web3.js與智慧合約互動

工具:Truffle v4.0.4  
ganache-1.1.0-beta(ui介面版)
nodejs 8.9.4
npm 5.6.0   
web3 1.0.0

思路:

1、先用truffle建立一個以太坊智慧合約專案,部署在ganache測試網路。

2、用npm建立另外一個專案,使用web3和智慧合約互動

建立truffle專案:

1、mkdir truffle_test & cd truffle test

2、初始化:truffle init

3、編寫智慧合約,在contracts資料夾下新建智慧合約:Data.sol:(功能:存、取一個字串)

pragma solidity ^0.4.17;

contract Data{

  string public data;

  function Data()public{
    data = "init data";
  }
  function setData(string str) public payable{
    data = str;
  }

  function getData() public view returns (string) {
    return data;
  }
}

4、編譯:truffle compile

5、部署在測試網路上

(1)開啟ganache

(2)修改migrations資料夾下的部署配置

var Migrations = artifacts.require("./Migrations.sol");
var Data = artifacts.require("./Data.sol");

module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(Data);
};

(3)修改truffle.js配置檔案,新增連線網路資訊:

module.exports = {
    networks: {
        development: {
          host: "localhost",
          port: 7545,
          network_id: "*"
        }
    }
};

(4)執行truffle migrate(如果執行失敗,可以試試truffle migrate --reset)

現在truffle專案已經做好,接下來使用web3和智慧合約進行互動。

web3與智慧合約互動

新增web3到專案中:

1、mkdir web3test & cd web3test

2、初始化 npm init

3、下載web3.js到專案中:

npm install web3 --save

以上命令會將web3.js下載到web3test/node_modules目錄下,其中--save引數會web3.js新增到package.json配置檔案中。

4、建立web3物件

要使用web3.js與區塊鏈互動,需要先建立web3物件,然後連線到以太坊節點。


在web3test目錄下新建index.js檔案,在其中輸入以下程式碼:

var Web3 = require("web3");
var web3 = new Web3();
web3.setProvider(new Web3.providers.HttpProvider("http://localhost:7545"));

5、獲取已部署的智慧合約例項

var abi = [{"constant":true,"inputs":[],"name":"getData","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"str","type":"string"}],"name":"setData","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"data","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}];
var address = '0x345ca3e014aaf5dca488057592ee47305d9b3e10';
var data = new web3.eth.Contract(abi,address);

其中abi是truffle專案中build目錄下Data.json檔案中的abi,複製過來即可。address是合約部署的地址。通過abi和合約地址就可以獲取合約的例項data。下面就可以通過data來呼叫合約裡面的內容了。

6、呼叫合約函式

data.methods.getData().call(null,function(error, result){
  console.log("the data:"+result);
 });

data.methods.setData("hello blockchain").send({from: '0x627306090abaB3A6e1400e9345bC60c78a8BEf57'}).on('transactionHash', function(hash){
  console.log("hash:", hash);
  data.methods.getData().call(null,function(error, result){
   console.log("the data:"+result);
 });
});

call()和send()的作用可以從官方文件中檢視。send裡面的from是傳送交易的地址,這裡我寫的是ganache中第0個賬戶的地址。

以上的執行結果是:

the data:init data
the data:hello blockchain
hash: 0x86a8674614c5ac4772cdf3aba6bf2786d366460bb524e49b8012b5dbe89b64dd

==================進階:web3+ipfs=========================

思路:

由於往區塊鏈儲存資料是有代價,所以不應該將大量的資料上傳。可以將資料儲存在ipfs上面得到一個hash值,將hash儲存在區塊鏈上,大大減少儲存量。

1、存資料:從本地獲取檔案,上傳到ipfs上面,得到檔案的hash值,將hash值儲存在區塊鏈上

2、取資料:從區塊鏈獲取hash值,根據hash從ipfs上讀取資料,儲存在本地

專案流程:

mkdir test_eth_ipfs & cd test_eth_ipfs

truffle專案建立和上面例子一樣,重新執行一遍即可。

還是在test_eth_ipfs這個目錄中繼續操作:

1、npm init

2、匯入web3介面(使用web30.20.1版本,因為在使用1.0版本是有些錯誤一直調不出來,乾脆還是用0.20版本吧)

npm install [email protected] --save

3、匯入ipfs介面

npm install ipfs-api --save

4、建立一個對ipfs操作的js檔案,方便下面操作

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

exports.add = function(buffer){
  return new Promise(function(resolve, reject){
    try {
      ipfs.add(buffer, function(err, files){
        if(err || typeof files == 'undefined'){
          reject(err);
        }else{
          resolve(files[0].hash);
        }
      })
    } catch (e) {
      reject(e);
    }
  })
}
exports.get = function(hash){
  return new Promise(function(resolve, reject){
    try {
      ipfs.get(hash, function(err, files){
        if(err || typeof files == 'undefined'){
          reject(err);
        }else{
          resolve(files[0].content);
        }
      })
    } catch (e) {
      reject(e);
    }
  })
}

5、建立index.js檔案,實現智慧合約和web3+ipfs互動

var ipfsFile = require("./ipfsFile");
var fs = require('fs');
//var data = artifacts.require("dataOperator");
var contract = require('truffle-contract');
var Web3 = require('web3');
var web3 = new Web3();
var provider = new Web3.providers.HttpProvider('http://localhost:7545');
web3.setProvider(provider);

let addPath = './storage/add/file1';
let getPath = './storage/get/file2';
let buff = fs.readFileSync(addPath);

 var contractJSON = JSON.parse(fs.readFileSync("./build/contracts/dataOperator.json"));
 var contract_abi = contractJSON.abi;

var data = contract(contractJSON);
data.setProvider(provider);

var data_instance;
var eth_accounts;
web3.eth.getAccounts(function(err, accounts){
  if(err){
    console.log(err);
  }
  eth_accounts = accounts;
  data.deployed()
  .then(function(instance){
    data_instance = instance;
  }).then(function(){
    return ipfsFile.add(buff);
  }).then(function(hash){
    console.log('hash1', hash);
    data_instance.setData(hash,{from:eth_accounts[0]});
  }).then(function(){
    return data_instance.getData();
  }).then(function(hash){
    console.log('hash2',hash);
    return ipfsFile.get(hash);
  }).then(function(data_info){
    fs.writeFileSync(getPath, data_info);
    console.log('data_info:',data_info.toString('utf-8'));
  }).catch(function(err){
    console.log(err);
  })
})

6、執行:

ipfs daemon(啟動ipfs)

node index

console中會輸出兩個相同的hash值,然後/storage/get中會出現一個與/storage/set中一樣的檔案