【以太坊开发】如何开发一个编译以太坊智能合约并且发布的平台(二)

接上一章的内容,这篇介绍 deploy相关和结果演示。

 

deploy一个合约的过程中,需要计算发布的消耗和nonce值。

当进行每笔交易时,发送人设定Gas Limit 和Gas Price,将 Gas Limit*Gas Price ,就得到了ETH交易佣金的成本。

nonce:以太坊要求一个账户的每笔交易有一个连续的计数。每个节点将根据计数顺序严格执行来自一个用户的交易。

 

app.js中有下面两个函数:

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

function etherSpentInPendingTransactions(address, callback)
{
    web3.currentProvider.sendAsync({
          method: "txpool_content",
           params: [],
           jsonrpc: "2.0",
           id: new Date().getTime()
    }, function (error, result) {
        console.log(result)
        if(typeof(result.result.pending)!="undefined" && result.result.pending)
        {
            if(result.result.pending[address])
            {
                var txns = result.result.pending[address];
                var cost = new BigNumber(0);
                
                for(var txn in txns)
                {
                    cost = cost.add((new BigNumber(parseInt(txns[txn].value))).add((new BigNumber(parseInt(txns[txn].gas))).mul(new BigNumber(parseInt(txns[txn].gasPrice)))));
                }

                callback(null, web3.fromWei(cost, "ether"));
            }
            else
            {
                callback(null, "0");
            }
        }
        else
        {
            callback(null, "0");
        }
    })
}

上面函数的流程:

1 使用sendAsync异步调用JSON PRC,调用的方法是 :txpool_content,这个方法用于查询交易池中待处理的交易,返回的结果属性有pending和queqed。想了解这个函数可以查看:https://github.com/ethereum/go-ethereum/wiki/Management-APIs#txpool_content

2  通过返回结果的属性 pending和账户的地址获取所以交易:

var txns = result.result.pending[address];对交易的结果进行循环,累加每个交易的value和gas消耗,就是所有将要打包到下个块的交易的总消耗。

在介绍一下getNonce函数:
function getNonce(address, callback)
{
    web3.eth.getTransactionCount(address, function(error, result){
        var txnsCount = result;

        web3.currentProvider.sendAsync({
              method: "txpool_content",
              params: [],
              jsonrpc: "2.0",
              id: new Date().getTime()
        }, function (error, result) {
            if(result.result.pending)
            {
                if(result.result.pending[address])
                {
                    txnsCount = txnsCount + Object.keys(result.result.pending[address]).length;
                    callback(null, txnsCount);
                }
                else
                {
                    callback(null, txnsCount);
                }
            }
            else
            {
                callback(null, txnsCount);
            }
        })
    })
}

 

eth中每个交易的nonce是累加的,它是把挖出的交易总数和待定的交易总数加起来得到的。

所以对于deploy函数来说,只需要利用上面两个函数构造交易的消耗cost和nonce值然后调用sendRawTranstaction,当然还需要对交易签署,需要提供秘钥,所以界面设计也会需要账户秘钥。代码如下:

app.get("/deploy", function(req, res){
    var code = req.query.code;
    var arguments = JSON.parse(req.query.arguments);
    var address = req.query.address;

    var output = solc.compile(code, 1);

    var contracts = output.contracts;

    for(var contractName in contracts)
    {
        var abi = JSON.parse(contracts[contractName].interface);
        var byteCode = contracts[contractName].bytecode;

        var contract = web3.eth.contract(abi);

        var data = contract.new.getData.call(null, ...arguments, {
            data: byteCode
        });
        console.log(data);
        console.log(web3.eth.defaultAccount)
        var gasRequired = web3.eth.estimateGas({
            from:address,
            data: "0x" + data
        });

        web3.eth.getBalance(address, function(error, balance){
            var etherAvailable = web3.fromWei(balance, "ether");
            etherSpentInPendingTransactions(address, function(error, balance){
                etherAvailable = etherAvailable.sub(balance)
                if(etherAvailable.gte(web3.fromWei(new BigNumber(web3.eth.gasPrice).mul(gasRequired), "ether")))
                {
                    getNonce(address, function(error, nonce){
                        var rawTx = {
                            gasPrice: web3.toHex(web3.eth.gasPrice),
                            gasLimit: web3.toHex(gasRequired),
                            from: address,
                            nonce: web3.toHex(nonce),
                            data: "0x" + data
                        };

                        var privateKey = ethereumjsUtil.toBuffer(req.query.key, 'hex');
                        var tx = new ethereumjsTx(rawTx);
                        tx.sign(privateKey);

                        web3.eth.sendRawTransaction("0x" + tx.serialize().toString('hex'), function(err, hash) {
                            res.send({result: {
                                hash: hash,
                            }});
                        });
                    })
                }
                else
                {
                    res.send({error: "Insufficient Balance"});
                }
            })
        })

        break;
    }
})

到这里基本流程已经很清晰了。具体的代码可以到git上下载:https://github.com/figo050518/deployContract

 配置app.js的web3地址。

进入项目根目录 执行 npm install

node app.js 启动前端服务。

我定义的端口是7070。下面是笔者执行的截图:

 

到这里就完成了一个编译 部署合约的平台,前端页面没有过多介绍,读者可以看下源码。

posted @ 2018-11-30 11:18  像我这样的人  阅读(340)  评论(0编辑  收藏  举报