基于以太坊区块链,使用web3.js在geth服务器上执行合约方法以及事件监听

写在最前:以下所有代码基于web3.js与geth交互使用websocket方式, 版本:1.1.0-beta.22测试通过并已成功在生产环境运行

1.启动geth服务器

geth --datadir /path/to/datadir/ --rpc --rpcapi db,eth,net,personal,web3 --ws --wsapi db,eth,net,personal,web3 --wsorigins=*

2.web3.js连接geth服务器

2.1首先使用合约部署后得到的json文件

connect.js

exports.getWeb3AndContract = (name) => {
    const Web3 = require("web3");
    const fs = require("fs");
    var address = "contract address";//合约地址,发布合约后得到的地址
    var contractFileContent = JSON.parse(fs.readFileSync("path/to/contract.json"));
    var web3 = new Web3();
    web3.setProvider(new Web3.providers.WebsocketProvider("ws://localhost:8546"));
    var contract = new web3.eth.Contract(contractFileContent.abi, address);
    return {"web3":web3, "contract":contract};
}

2.2编写合约方法、合约事件

method.js

exports.RollLottery = function (contract, web3, taskGuid) {
    web3.eth.getCoinbase().then((resp) => {
                console.log("get current gas price");
                web3.eth.getGasPrice((err, res) => { //获取当前的gasPrice
                    var currentGasPrice = 0;
                    if (err === null) {
                        console.log("current gas price is: " + res);
                        currentGasPrice = res * 5;
                    }
                    console.log("[RollLottery]");
                    contract.methods.RollLottery(taskGuid) //taskGuid,你的执行参数,注意数据类型必须和合约内对应方法的参数类型一致,否则会发生错误
                        //.send({from:resp,value:web3.utils.toWei(payNumber, 'ether'), gas:150000})
                        .send({from:resp,value:0, gasPrice:currentGasPrice,gas:150000})
                        .once('transactionHash', (hash)=>{
                                                        //当合约正确执行后,这里会返回合约执行后生成的hash值
                            console.log('once transactionHash: ' + hash);
                        })
                        .once('receipt', (receipt)=>{
                            //console.log("once receipt: " + receipt);
                        })
                        .on('confirmation', (confNumber, receipt)=>{
                                                        //当合约执行发出的区块被矿工挖出并确认时,这里会有返回值
                            //console.log("on confirmation: " + confNumber);
                            //console.log("on confirmation:");
                            //console.log(receipt);
                        })
                        .on('error', (error)=>{
                                                        //合约执行失败,这里会有返回值
                            console.log('on error: ' + error);
                        })
                            .then(function(result, error){
                                                        //错误发生时的异常捕获   
                            // console.log("error:");
                            // console.log(error);
                            // console.log("result:");
                            // console.log(result);

                                                });
                }).then((ex) => {
                                        //获取当前gasPrice的错误异常捕获
                    console.log("ge current gas price error: " + ex);
                });       
            }).catch((err)=>{console.log('getCoinbase error: ' + err);});    
}

watch.js

exports.LotteryLogRandNumberBC = (web3, contract) => {
    var _this = this;
    contract.events.LogRandNumberBC({fromBlock:"latest", toBlock:"latest"})
    .on('data', (event) => {
                //event.returnValues将会是一个json对象,里面包含合约中事件返回值,注意,键名和合约中的变量名称完全一致。
        console.log("[(Lottery)LogRandNumberBC Event] on data event: (returnValues)");
        console.log(event.returnValues);
        var taskGuid = event.returnValues.taskID;
        var winNumber = event.returnValues.randomNum;
        var txHash = event.transactionHash;
        //todo something.
    })
    .on('changed', (event) => {
        // console.log("[(Lottery)LogRandNumberBC Event] on changed event:");
        // console.log(event);
    })
    .on('error', (error) => {
        console.log("[(Lottery)LogRandNumberBC Event] on error:");
        console.log(error);
    });
    return false;
};

2.3调用合约方法

lottery_server.js

//引入connect.js
const web3AndContract = require("connect");
//引入合约方法
const Methods = require("method");
//初始化连接
var lottery = web3AndContract.getWeb3AndContract("lottery");
//调用合约方法
blackJackAllMethods.RollLottery(lottery.contract, lottery.web3, taskGuid);

执行合约方法部分数据返回:

method result

2.4开始监听合约事件

lottery_watcher.js

//引入connect.js
const web3AndContract = require("connect");
//引入合约事件
const lotteryAllWatchers = require("watch");
//初始化合约事件
var lottery = web3AndContract.getWeb3AndContract("lottery");
//调用合约事件,开始监听
lotteryAllWatchers.LotteryLogRandNumberBC(lottery.web3, lottery.contract);

监听合约事件部分数据返回:

event result

注意:执行监听任务时,脚本将处于等待接收消息状态,建议使用守护进程方式以后台形式运行。

3.部分合约代码(solidity)

pragma solidity ^0.4.2;


contract Lottery {

    /*
     * checks only owner address is calling
    */
    modifier onlyOwner 
    {
        require(msg.sender == owner);
         _;
    }

    /*
     * game vars
    */
    address public owner;

    uint private randomNumber;  //上一次的randomNumber会参与到下一次的随机数产生

    /*
     * events
    */
    event LogRandNumberBC(uint64 taskID,uint16 randomNum); //这里是event事件定义,当事件执行后,"taskID、randomNum"数据将会被返回

    /*
     * init
    */
    constructor() public {
        owner = msg.sender;
    }

    function RollLottery(uint64 taskID) public
        onlyOwner
    {
        uint16 randResult;

        randomNumber     = uint(keccak256(randomNumber,taskID,block.difficulty)) * uint(blockhash(block.number - 1));
        randResult         = uint16(randomNumber % 1000);

        emit LogRandNumberBC(taskID,randResult);
    }


    function ()
        public payable
    {
        return;
    }


    /* only owner address can set owner address */
    function ownerChangeOwner(address newOwner) public
        onlyOwner
    {
        owner = newOwner;
    }

    /* only owner address can suicide - emergency */
    function ownerkill() public
        onlyOwner
    {
        selfdestruct(owner);
    }

}

4.在区块链服务器上查看合约运行情况

以太坊区块链有两个环境地址:一个测试地址,一个正式地址

  • 测试地址: https://ropsten.etherscan.io,访问https://ropsten.etherscan.io/tx/你的方法或事件hash,可以查询结果
  • 正式地址: https://etherscan.io ,访问https://etherscan.io/tx/你的方法或事件hash,可以查询结果

5.更多web3.js文档

https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html

转载请注明原文地址:https://blog.keepchen.com/a/using-web.js-over-Ethernet-block-chain.html