1. 程式人生 > 實用技巧 >區塊鏈3

區塊鏈3

拍賣系統

講義:https://github.com/confucianzuoyuan/blockchain-tutorial/tree/master/%E4%BB%A5%E5%A4%AA%E5%9D%8A%E6%95%99%E7%A8%8B/%E6%8B%8D%E5%8D%96%E5%BA%94%E7%94%A8

知識點:

全結點儲存有完整的區塊鏈,輕結點則部分。

安裝[email protected],ganache-cli,[email protected]。其中npm install:若無-g,則把包安裝到當前目錄,若有-g,則全域性安裝,裝到其他位置。

執行ganache-cli:搭建以太坊環境,開啟8545埠。

npm init:初始化package.json。

建立一個簡易合約:

solcjs --abi aa.sol:編譯aaa.sol後生成abi檔案

node a.js:執行a.js檔案

在node中呼叫合約中的test方法:

varcontractInstance=web3.eth.contract(abi).at(合約的部署地址); contractInstance.test({from:web3.eth.accounts[0]}); // 呼叫合約函式時,要傳入是誰呼叫了該函式{from:web3.eth.accounts[0]}

js引擎執行js檔案,進而呼叫合約的test方法:

varMyContract=newweb3.eth.Contract(abi, 合約地址); MyContract.methods.test().call().then(i=>alert(i)); //test方法的返回值給i,隨後alert(i)

由於require不能被js引擎識別,只能被node識別,所以需要webpack翻譯:webpack index.js indexed.js,然後html頁面引用indexed.js,同時還要把Web3引入進來:

<scripttype="text/javascript"src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>

IPFS:分散式檔案系統,存到各個節點,類似於世界硬碟

安裝:https://pan.baidu.com/s/1H9DRYZLKmGvdEzP0-DzjJA,再配置環境變數path,輸入ipfs init初始化倉庫,輸入ipfs daemon開啟守護程序,隨後可以訪問127.0.0.1:5001/webui
上傳檔案到ipfs,同時會得到一個雜湊值:

通過此雜湊訪問此檔案:

遠端訪問:

本地訪問:

http://localhost:8080/ipfs/QmekZaRsMQXHwwDT7qu41khcPspwFLANnv1QEv8xdAR7Cz

安裝ipfs-api庫:npm install -g ipfs-api

js檔案裡的require無法由瀏覽器直接識別,需要通過webpack index.js index2.js,轉到index2.js才行。

步驟:

執行ganache-cli開啟區塊鏈環境

生成abi檔案:solc --abiEcommerceStore.sol

部署合約:node deploy.js,其中deploy.js:

// 部署合約
var Web3=require('web3') // 獲得模組
var fs = require('fs')
var web3=new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
var solc = require('solc')
//sudo chmod 666 aaa.sol// linux要寫這句:修改檔案許可權使能讀
var sourceCode=fs.readFileSync('EcommerceStore.sol').toString() //拿到sol檔案
var compiledCode=solc.compile(sourceCode) //用編譯器編譯它
var abi = JSON.parse(compiledCode.contracts[':EcommerceStore'].interface) //獲得其中編譯的abi
var byteCode = compiledCode.contracts[':EcommerceStore'].bytecode//獲得位元組碼
var VotingContract = web3.eth.contract(abi)//建立合約物件
var deployTxObj = {data:byteCode,from:web3.eth.accounts[0],gas:3000000}//構建一個交易
VotingContract.new(deployTxObj); //定義合約例項, 第一個引數可選,是合約的建構函式要接受的引數

 此時ganache-cli裡面就有了合約地址:

為了把檔案上傳到ipfs,需要開啟ipfs:ipfs daemon

上傳幾個檔案並得到對應的雜湊:ipfs add 檔案地址

給合約變數賦值:node seed.js,其中seed.js:
// 執行node來新增東西(給合約變數賦值)

var fs = require('fs')
var solc = require('solc')
var Web3=require('web3') // 獲得模組
var web3=new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
//sudo chmod 666 aaa.sol// linux要寫這句:修改檔案許可權使能讀
var sourceCode=fs.readFileSync('EcommerceStore.sol').toString() //拿到sol檔案
var compiledCode=solc.compile(sourceCode) //用編譯器編譯它
var abi = JSON.parse(compiledCode.contracts[':EcommerceStore'].interface) //獲得其中編譯的abi
// node compile.js後,可從ganache-cli可以獲得合約地址:0x32ccbdb064098d160fe946e814137da6880701c1
var contractAddr = "0xd0eb6cb24bdec0f6985792777a7da4329d3b75be";
var contractInstance = web3.eth.contract(abi).at(contractAddr);


// 開始新增產品
current_time = Math.round(new Date() / 1000);
amt_1 = web3.toWei(1, 'ether');

contractInstance.addProductToStore('iphone 5', 'Cell Phones & Accessories', 'QmekZaRsMQXHwwDT7qu41khcPspwFLANnv1QEv8xdAR7Cz', 'QmbLRFj5U6UGTy3o9Zt8jEnVDuAw2GKzvrrv3RED9wyGRk', current_time, current_time + 200, 2*amt_1, 0,{from:web3.eth.accounts[0]}).call().then();
contractInstance.addProductToStore('iphone 5s', 'Cell Phones & Accessories', 'QmPyt3L7VYM31KndYoEpAv23HSDSdhx7UYhpSYrwpUhpCt', 'QmbLRFj5U6UGTy3o9Zt8jEnVDuAw2GKzvrrv3RED9wyGRk', current_time, current_time + 200, 2*amt_1, 0,{from:web3.eth.accounts[0]}).call().then();

建立index.js渲染頁面:

// 與合約互動從而渲染頁面

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


window.addEventListener('load', function() {
    // 若已經有web3物件(比如metamask給瀏覽器注入了web3),則使用現成的,否則新建一個
    if (typeof web3 !== 'undefined') {
        console.log("web3已經存在");
        window.web3 = new Web3(web3.currentProvider);
    } else {
        console.log("web3不存在,現在建立");
        var Web3=require('web3');
        window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
    }

    var abi = JSON.parse('[{"constant":true,"inputs":[],"name":"getT","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"totalBids","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_category","type":"string"},{"name":"_imageLink","type":"string"},{"name":"_descLink","type":"string"},{"name":"_auctionStartTime","type":"uint256"},{"name":"_auctionEndTime","type":"uint256"},{"name":"_startPrice","type":"uint256"},{"name":"_productCondition","type":"uint256"}],"name":"addProductToStore","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"getProduct","outputs":[{"name":"","type":"uint256"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint8"},{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"productIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"highestBidderInfo","outputs":[{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_bid","type":"bytes32"}],"name":"bid","outputs":[{"name":"","type":"bool"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_amount","type":"string"},{"name":"_secret","type":"string"}],"name":"revealBid","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"test","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]')
    var contractAddr = "0xd0eb6cb24bdec0f6985792777a7da4329d3b75be";
    var MyContract = new web3.eth.Contract(abi, contractAddr);
    // 賦給全域性
    window.web3 = web3;
    window.MyContract = MyContract;
    renderStore();
});


function renderStore() {
    // 得到產品:呼叫合約裡面的getProduct方法,然後非同步進入then,其中getProduct的返回值給i
    // MyContract.methods.getProduct(1).call().then(p=>console.log(p));
    MyContract.methods.getProduct(1).call().then(p=>$("#product-list").append(buildProduct(p)));
    MyContract.methods.getProduct(2).call().then(p=>$("#product-list").append(buildProduct(p)));
}

function buildProduct(product) {
    let node = $("<div/>");
    node.addClass("col-sm-3 text-center col-margin-bottom-1");
    node.append("<img src='http://localhost:8080/ipfs/" + product[3] + "' width='150px' />");
    node.append("<div>" + product[1]+ "</div>");
    node.append("<div>" + product[2]+ "</div>");
    node.append("<div>" + product[5]+ "</div>");
    node.append("<div>" + product[6]+ "</div>");
    node.append("<div>Ether " + product[7] + "</div>");
    return node;
}

為了解釋require,webpack index.js indexed.js

html頁面引入js檔案:

<head>
 <title>去中心化</title>

 <link href='https://fonts.proxy.ustclug.org/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
 <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

 <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
 <script src="indexed.js"></script>

</head>

開啟html