以太坊学习(::)简单项目实战

简单项目实战


目的:以html+js构建网页,展示链上信息。


一、合约

  • 合约内容:
  • 用结构体user记录【用户】个人信息,映射为users
  • 用结构体consignment记录【电能】交易订单,映射为orders
  • 利用call获取订单的信息
  • 合约如下:
pragma solidity ^0.4.13;
//pragma experimental ABIEncoderV2;
contract basecontract{
    address administrator;
    enum consignmentstatus{Waiting,Trading,Finished,Failed}
    enum accountTradeStatus {Waiting,Buying,Selling}
    event userRegisterLog(address addr);
    event generatePowerConfirm(bool check,uint _value);
    event getuserInfo(uint generateDepositPower,uint usablePower,uint debtPower);
    event consumePowerEvent(address indexed addre,bool success,uint consumelocalpower,uint consumepurchasepower);
    struct user{
        string name;
        string useraddress;
        uint generateDepositPower;
        uint totalgeneratePower;
        uint usablePower;
        uint totalConsumePower;
        uint debtPower;
        bool generateRight;
        bool useRight;
        accountTradeStatus status;
        //bool generatingPower;
        //bool usingPower;
        uint orderID;
    }
    struct consignment{
        address consignmentSender;
        address consumer;
        consignmentstatus status;
        uint energyRemainToTrade;
        uint totalEnergytoSell;
        uint price;
        uint dealTime;
    }
    mapping(address=>user) public users;
    mapping(uint=>consignment) public orders;
    uint public latestOrderID =1;
    function basecontract() { administrator = msg.sender; }
    

    function getUserInfo(address _addr) view public returns(uint,uint,uint)
    {
        require(msg.sender==administrator || msg.sender==_addr);
        return(users[_addr].generateDepositPower,
        users[_addr].usablePower,users[_addr].debtPower);
    }
    function getConsignment(uint _id) view public returns(address,uint,uint,uint,uint,consignmentstatus)
    {
        require(_id<=(2**255-1)&&_id<latestOrderID);
        return(
            orders[_id].consignmentSender,
            orders[_id].energyRemainToTrade,
            orders[_id].totalEnergytoSell,
            orders[_id].price,
            orders[_id].dealTime,
            orders[_id].status
            );
    }

}
//合约非完整版,只展示了call部分方法

 

  • 假定users以及orders两个映射已经有内容,我们直接call即可得到对应信息。
  • 内容如下:

二、以node.js架构本地服务器【node.js安装不再赘述】

(1) 新建项目文件夹

mkdir htmlTest

cd htmlTest

(2)安装express

 npm install express

(3) 新建server.js

var express = require("express");
var app = express();

app.use(express.static("public")).listen(8080);

(4)新建文件夹public,用来存放index.html以及各种js文件等

三、编写index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Test</title>
</head>

<body>
  <h1>交易系统Test</h1>
  <hr>
  </hr>
  <h2>用户信息
  </h2>
  <table border="0">
    <tr>
      <td><button type="button" id="getAccountBtn">getAccout</button></td>
      <td><select id="eth_account"></select></td>
      <td>
        <div id="eth_balance">balance</div>
      </td>
    </tr>
  </table>
  <ul id="userinfo">
    <li id="userinfo_generateDepositPower">本地储存电量:</li>
    <li id="userinfo_usablePower">已购可用电量:</li>
    <li id="userinfo_debtPower">欠费电量:</li>
  </ul>
  <hr>
  </hr>
  <h2>寄售列表<button type="button" id="refresh_consignment">刷新</button>
  </h2>
    <table id="consignmentList" border="1">
      <tr id="table_head">
        <td>寄售账户</td>
        <td>待传输电量</td>
        <td>总交易电量</td>
        <td>寄售价格</td>
        <td>交易时间</td>
        <td>交易状态</td>
      </tr>
    </table>
</body>

<script src="https://cdn.jsdelivr.net/gh/ethereum/[email protected]/dist/web3.min.js" integrity="sha256-nWBTbvxhJgjslRyuAKJHK+XcZPlCnmIAAMixz6EefVk=" crossorigin="anonymous"></script>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="eth.js"></script>

</html>

注意事项:

  • 基本划分两部分,一是获取用户信息,二是获取订单信息
  • 直接引入了web3.js,就不用在js里面使用require("web3")了,因为这里只是javascript文件,与直接在node.js环境下运行有所区别。<script src="https://cdn.jsdelivr.net/gh/ethereum/[email protected]/dist/web3.min.js" integrity="sha256-nWBTbvxhJgjslRyuAKJHK+XcZPlCnmIAAMixz6EefVk=" crossorigin="anonymous"></script> 
  • 引入jquery库
  • eth.js为自己写的js脚本

界面如下:

四、eth.js文件编写

关于web3.js的使用,可参考:利用Web3.js与节点交互【1】 、利用Web3.js与节点交互【2】

以及web3.js 1.0版本官方文档:

中文版:http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/8/

官方版:https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract

(1)web3定义以及连接本地节点

let web3;
//文档构筑完成就执行如下:
$(document).ready(function(){
  if(typeof web3 !=='undefined'){ //检查是否已有web3实例
      web3=new Web3(web3.currentProvider);
  }else{
      //否则就连接到给出节点
      web3=new Web3();
      web3.setProvider(new Web3.providers.WebsocketProvider("ws://localhost:8546"));//注意这里注意端口不用一致,直接默认8546即可(若刚刚启动节点的rpc端口是8545的情况下)
  }
//检查连接情况
web3.eth.getBlock(0, function(error, result){
    if(!error)
        console.log("connect should be success");
    else
        console.log("something wrong,the connection might be failed");
})

(2)实例化合约

var myContract;
//实例化合约
var abi;
$.ajax({
    url: 'contract.json',
    async: false,
    success: function (data) {
        abi = data;
    }
});
var myContractAddress="0xbb877827e6ef3870c96c7a7726e8e2bed140fb9e";
myContract=new web3.eth.Contract(abi);
myContract.options.address=myContractAddress;
});
  • 关于abi,contract.json文件为自己在public文件夹下创建,内容为合约的abi,即json,可在remix-ide中获取
  • 合约地址为该合约部署到私有链上的地址
  • 如果这一段可正常执行,那么接下来就可以用myContract直接操作合约

(3) getAccount按钮:获取节点下的账户,然后添加到下拉列表框中

//get node_accounts
let account;
$("#getAccountBtn").click(function(){
  console.log('attempt to get accounts');
web3.eth.getAccounts(function(error, result){
    if(!error){
      //清空列表框
      $("#eth_account").empty();
      //重新插入
      for(var i=0;i<result.length;i++){
        $("#eth_account").append("<option value='"+result[i]+"'>"+result[i]+"</option>");
        //console.log(result[i]);
      }
        account=result;
    }
    else{
        console.log("failed to get Accoutns");
    }
})
});

(4)获取账户余额:下拉列表框选中项改变时触发

  • 获取的余额为下拉列表框当前选中的地址项
//get balance
$("#eth_account").change(function(event) {
  var _account=$("#eth_account").val();
    web3.eth.getBalance(_account).then(function(balance){
        console.log('account: ',_account,' balance:',web3.utils.fromWei(balance),'ether');
        $("#eth_balance").text(web3.utils.fromWei(balance)+' ether')
    });
    getUserInfo();
});

(5)获取用户信息:这里就要开始使用myContract了,因为调用的是合约的Call方法

  • 获取到的信息填充到列表下
//获取账户信息
function getUserInfo(){
  var _account=$("#eth_account").val();
  myContract.methods.getUserInfo(_account).call({from:_account},
    function(error,result){
      $("#userinfo_generateDepositPower").text('本地储存电量:'+result[0]);
      $("#userinfo_usablePower").text('已购可用电量:'+result[1]);
      $("#userinfo_debtPower").text('欠费电量:'+result[2]);

      console.log(result);
    }
  );
}

 (6)获取寄售订单:点击刷新按钮触发,然后将获取到的订单信息填入表格中

//获取寄售订单
$("#refresh_consignment").click(function(event) {
  var _account=$("#eth_account").val();
  for(var i=1;i<=1;i++){
  myContract.methods.getConsignment(i).call({from:_account},
    function(error,result){
        var tr=$("<tr>\
        <td>"+result[0]+"</td>"+
        "<td>"+result[1]+"</td>"+
        "<td>"+result[2]+"</td>"+
        "<td>"+result[3]+"</td>"+
        "<td>"+result[4]+"</td>"+
        "<td>"+result[5]+"</td></tr>");
        $("#consignmentList").append(tr);
      console.log(result);
    }
  );
}
});

(7)eth.js全部代码如下:

let web3;
var myContract;
$(document).ready(function(){
  if(typeof web3 !=='undefined'){ //检查是否已有web3实例
      web3=new Web3(web3.currentProvider);
  }else{
      //否则就连接到给出节点
      web3=new Web3();
      web3.setProvider(new Web3.providers.WebsocketProvider("ws://localhost:8546"));//注意这里注意端口不用一致,直接默认8546即可(若刚刚启动节点的rpc端口是8545的情况下)
  }

//var connected = web3.isConnected();
web3.eth.getBlock(0, function(error, result){
    if(!error)
        console.log("connect should be success");
    else
        console.log("something wrong,the connection might be failed");
})
//实例化合约
//var abi=JSON.parse(fs.readFileSync("basecontract_sol_basecontract.abi").toString())
var abi;
$.ajax({
    url: 'contract.json',
    async: false,
    success: function (data) {
        abi = data;
    }
});
var myContractAddress="0xbb877827e6ef3870c96c7a7726e8e2bed140fb9e";
myContract=new web3.eth.Contract(abi);
myContract.options.address=myContractAddress;

});
//get node_accounts
let account;
$("#getAccountBtn").click(function(){
  console.log('attempt to get accounts');
web3.eth.getAccounts(function(error, result){
    if(!error){
      //清空列表框
      $("#eth_account").empty();
      //重新插入
      for(var i=0;i<result.length;i++){
        $("#eth_account").append("<option value='"+result[i]+"'>"+result[i]+"</option>");
        //console.log(result[i]);
      }
        account=result;
    }
    else{
        console.log("failed to get Accoutns");
    }
})
});

//get balance
$("#eth_account").change(function(event) {
  var _account=$("#eth_account").val();
    web3.eth.getBalance(_account).then(function(balance){
        console.log('account: ',_account,' balance:',web3.utils.fromWei(balance),'ether');
        $("#eth_balance").text(web3.utils.fromWei(balance)+' ether')
    });
    getUserInfo();
});

//获取账户信息
function getUserInfo(){
  var _account=$("#eth_account").val();
  myContract.methods.getUserInfo(_account).call({from:_account},
    function(error,result){
      $("#userinfo_generateDepositPower").text('本地储存电量:'+result[0]);
      $("#userinfo_usablePower").text('已购可用电量:'+result[1]);
      $("#userinfo_debtPower").text('欠费电量:'+result[2]);

      console.log(result);
    }
  );
}

//获取寄售订单
$("#refresh_consignment").click(function(event) {
  var _account=$("#eth_account").val();
  for(var i=1;i<=1;i++){
  myContract.methods.getConsignment(i).call({from:_account},
    function(error,result){
        var tr=$("<tr>\
        <td>"+result[0]+"</td>"+
        "<td>"+result[1]+"</td>"+
        "<td>"+result[2]+"</td>"+
        "<td>"+result[3]+"</td>"+
        "<td>"+result[4]+"</td>"+
        "<td>"+result[5]+"</td></tr>");
        $("#consignmentList").append(tr);
      console.log(result);
    }
  );
}
});

五、启动server.js

nodejs server.js

六、 浏览器输入:http://localhost:8080/

(1)点击getAccount

 

(2)点击寄售列表后面的刷新按钮:

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/84865425