【干货】以太坊发布和调用智能合约实操

文章目录

  • 一、安装Web3.js
  • 二、连接geth节点
  • 三、编写和编译智能合约
  • 四、发布智能合约
  • 五、调用智能合约
  • 六、自动编译智能合约

一、安装Web3.js

  Web3.js是一套用Javascript实现的API,用于与以太坊节点进行通信,并通过以太坊节点操作以太坊网络。Web.js内部使用JSON-RPC协议与以太坊节点(geth和其他类型的节点)进行通信。
  JSON-RPC是一个无状态且轻量级的远程过程调用(RPC)协议。该协议主要定义了一些数据结构及其相关的处理规则。允许运行在基于Socket、HTTP等诸多不同消息传输环境的同一进程中使用JSON作为数据格式。
  Web3.js将所有的JSON-RPC封装成Javascript API。Web3.js可以与所有种类的、支持JSON-RPC协议的以太坊节点通信。

  首先需要安装Node.js。

brew install node

  其次安装Web3.js。

brew install web3

  安装完Web3.js,在终端执行node命令进入Node.js交互环境(REPL),然后输入:

require("web3")

【干货】以太坊发布和调用智能合约实操_第1张图片

二、连接geth节点

  Web3.js不仅可以通过HTTP与以太坊节点连接,还可以通过IPC方式与以太坊节点连接。HTTP连接方式通过HttpProvider对象指定连接信息,IPC方式需要通过IPCProvider对象指定连接信息。
  IPCProvider类的构造方法需要一个IPC文件,在启动geth节点后,从日志输出中可以找到这个IPC文件,本例是geth.ipc。
  关于以太坊私有链的搭建参见【干货】Mac上搭建以太坊私有网络

  从日志信息可以看出,笔者的geth.ipc文件路径是/Users/andrewfeng/Documents/Ethereum/myeth/chaindata/geth.ipc,读者可将其替换为自己的目录。

  接下来我们测试同时使用HTTP和IPC方式与geth节点连接,并调用getAccount函数,用异步的方式获取geth节点的账户。

  编写javascript脚本文件connect_http_ipc.js如下:

var Web3 = require("web3");
var net = require('net');
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
web3.eth.getAccounts(
	function(error, response)
	{
		console.log(response)
	}
)

web3 = new Web3(new Web3.providers.IpcProvider('/Users/andrewfeng/Documents/Ethereum/myeth/chaindata/geth.ipc',net));
web3.eth.getAccounts(
	function(error, response)
	{
		console.log(response)
	}
)

【干货】以太坊发布和调用智能合约实操_第2张图片
  可见,两种方式都成功连接并打印出了geth节点的账户地址。

三、编写和编译智能合约

  如果通过geth节点或其他节点发布智能合约,不能通过Remix直接部署,而是需要使用相应的API发布智能合约。发布智能合约需要使用contract.new方法,而且必须先将智能合约源码文件(.sol文件)编译成二进制问价(.bin)才能发布。
  将.sol文件编译成EVM字节码的工作是在客户端完成的,而不是在以太坊节点或以太坊网络中完成的。

  用Solidity语言编写一个简单的计算阶乘的智能合约程序Factorial.sol.

pragma solidity ^0.6.3;

contract Factorial {
    function factorial(uint n) public returns(uint){
        if (n == 0 || n == 1)
            return 1;
        else
            return n * factorial(n-1);
    }
}

  这里可以使用强大的IDEA作为开发工具,安装插件Intellij-Solidity,即可编写Solidity代码。但还需要安装Solidity编译器。
  Solidity编译器是用于编译Solidity源代码文件的,可以将其编译为多种目标文件。因此需要安装solc,但命令行工具是solcjs。使用如下命令安装:

npm install -g solc

  例如,使用如下命令可将Factorial.sol文件编译生成abi文件。

solcjs --abi Factorial.sol

  但我们可以将其集成进IDEA的扩展工具中。打开Preferences,找到Tools > External Tools,点击”+“按钮,填入如下参数。
【干货】以太坊发布和调用智能合约实操_第3张图片
  通过执行Tools > External Tools > solidity即可编译执行。在项目的out/product目录下生成编译文件。
【干货】以太坊发布和调用智能合约实操_第4张图片

四、发布智能合约

  使用Web3.js API发布智能合约,首先要使用fs模块中的API装载Factorial_sol_Factorial.abi和Factorial_sol_Factorial.bin文件。
  装载完.bin和.abi文件后,在使用contract.new方法发布智能合约之前,要先使用web3.personal.unlockAccount函数解锁用于发布智能合约的账户,否则该账户不能用来发布智能合约,也不能用来转账。最后通过contract.new方法异步方式发布智能合约。

  编写javascript脚本文件install_contract.js如下:

var Web3 = require("web3");
var fs = require("fs");
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var code = '0x' + fs.readFileSync("Factorial_sol_Factorial.bin").toString();
var abi = JSON.parse(fs.readFileSync("Factorial_sol_Factorial.abi").toString());
var contract = web3.eth.contract(abi);
console.log('account balance:' + web3.eth.getBalance(web3.eth.accounts[0]))
web3.personal.unlockAccount(web3.eth.accounts[0],"3336515")//第二个参数为账户密码
var contract = contract.new({from: web3.eth.accounts[0], data: code, gas: 500000},
		function(e, contract){
			
    		if(!contract.address) {
    		    console.log("已经发起交易,交易地址:" + contract.transactionHash + "\n正在等待挖矿");
 			} else {
    			console.log("智能合约部署成功,地址:" + contract.address);
    
            }
 		 
 		}  
)

  核心是contract.new方法。该方法通过异步方式发布智能合约,通过第一个参数传递与智能合约相关的信息。尤其要指明的是gas属性,该属性需要指定发布智能合约需要付出的代价,单位是gas,这时以太坊的内部计量单位。
  要想知道发布某个智能合约大概需要多少gas,可以使用web3.eth.estimateGas函数预估。

var gasValue = web3.eth.estimateGas({data:code})
console.log('gas:' + gasValue)

  要想将智能合约发布在以太坊上,还需要挖矿,挖出一个区块才执行。

miner.start(2);admin.sleepBlocks(1);miner.stop()

在这里插入图片描述
  挖出后可以看到智能合约部署成功。

五、调用智能合约

  调用智能合约并不需要装载Factorial_sol_Factorial.bin文件,秩序装载Factorial_sol_Factorial.abi文件即可。.abi文件是普通的文本文件,用于描述智能合约的名字、函数、参数类型等信息。
  调用智能合约有两种方式:本地方式和以太坊网络方式。通过本地方式调用智能合约API,会直接返回计算结果;通过以太坊网络方式调用智能合约,结果都保存在以太坊网络中。

  编写javascript脚本文件install_contract.js如下:

var Web3 = require("web3");
var fs = require("fs");
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var abi = JSON.parse(fs.readFileSync("Factorial_sol_Factorial.abi").toString());
var contract = web3.eth.contract(abi);
var instance = contract.at('0x5c2a7ba57cd87fcf0918ab262a67caaf4bc9135e')
web3.personal.unlockAccount(web3.eth.accounts[0],"3336515")
console.log(instance.factorial.call(10).toString())
console.log(instance.factorial(10,{from:web3.eth.accounts[0],gas:8000000}))

六、自动编译智能合约

  可以直接使用Node.js的solc模块将编译智能合约的功能嵌入到程序中。

  首先安装solc模块:

npm install solc

  然后可以使用下面的代码引用solc模块:

var solc = require('solc');

  编写Greeter智能合约:

pragma solidity ^0.6.3;

contract Greeter {
    string public greeting;

    function Greeter(){
        greeting = "Hello World!";
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function getGreeting() constant returns (string) {
        return greeting;
    }
}

  编写javascript脚本文件greeter.js如下:

var Web3 = require("web3");
var solc = require('solc');
var fs = require("fs");
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var code = fs.readFileSync("Greeter.sol").toString();
var input = {
	'Greeter.sol': code,
}
var output = solc.compile({ sources: input });
var abi = JSON.parse(output.contracts['Greeter.sol:Greeter'].metadata).output.abi;
web3.personal.unlockAccount(web3.eth.accounts[0],"3336515")

var contract = web3.eth.contract(abi);
contract.new({from: web3.eth.accounts[0], data: '0x' + output.contracts['Greeter.sol:Greeter'].bytecode, gas: 200000},
		function(e, contractData){
			
    		if(!contractData.address) {
    		    console.log("已经发起交易,交易地址:" + contractData.transactionHash + "\n正在等待挖矿");
 			} else {
    			console.log("智能合约部署成功,地址:" + contractData.address);
    			var instance = contract.at(contractData.address);
    			console.log(instance.greet())
    		    instance.setGreeting('你好', transact={'from': web3.eth.accounts[0]},
    		    	function(e,data)
    		    	{
    		    		console.log(instance.greet())
    		    	}
    		    )
            }
 		}  
)

你可能感兴趣的:(区块链)