4.2 合约开发入门
4.2.1 注意事项
- 在编写智能合约前,需要对区块链基础有一定的了解。(附:ethereum-overviewSolidity)
- Ethereum Virtual Machine 是在以太坊上为智能合约提供运行时环境的虚拟机。迅雷链开放平台兼容EVM,但需遵循官方平台的平台使用约束。
- 账户类型分为外部账户(普通的交易账户地址)和合约账户。
- 创建合约就是向目标账户地址0发送交易的过程。
- 合约部署和调用过程中(改变合约内部状态变量)会消耗gas,gas_price*gas是每次交易产生的手续费。
4.2.2 compile
- 可以使用官方合约编译IDE Catalyst编写和部署调试合约。
- 可以使用浏览器编译调试运行智能合约环境Remix来快速编写合约,无依赖环境配置。
- 使用npm包solcjs,全局安装npm i -g solc,命令行使用solc编译对应合约。
- 使用 truffle 的 compile 命令。
- 本平台推荐使用Catalyst进行开发。
Catalyst使用指南 智能合约solidity开发框架truffle。 提供了一套完善的开发、调试、编译、部署、测试的本地环境。
4.2.3 安装truffle
npm i -g truffle
[root@opennode sandai]# truffle version
Truffle v4.1.5 (core: 4.1.5)
Solidity v0.4.21 (solc-js)
4.2.3 开始
使用truffle 初始化合约工程
mkdir simple-storage
cd simple-storage
truffle init
新建合约文件:可以使用
truffle create contract SimpleStorage
命令行新建,也可以直接新建文件 contract/SimpleStorage.sol// SimpleStorage.sol
pragma solidity ^0.4.21;
contract SimpleStorage {
uint myVariable;
function set(uint x) public {
myVariable = x;
}
function get() constant public returns (uint) {
return myVariable;
}
}
添加migrate脚本:可以使用
truffle create migration 2_deploy_contract
命令行方式新增,也可以直接新建文件 migrations/2_deploy_contract.js// 2_deploy_contract.js;truffle migrate命令的执行顺序与文件名有关,所以多个部署脚本需要按照顺序命名
var SimpleStorage = artifacts.require("SimpleStorage");
module.exports = function(deployer) {
deployer.deploy(SimpleStorage);
};
执行truffle compile编译合约,编译后的合约在build文件夹下。每个合约有一个对应的json文件,内含部署所需的bytecode,abiCode等
编辑 truffle.js ,设置truffle部署合约及与区块链交互的rpc连接。
[root@localhost opennode]# vi truffle.js
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*"
}
}
};
控制台开启truffle默认的区块链环境。
truffle develop
Truffle Develop started at http://127.0.0.1:9545/
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.
truffle(develop)>
这为truffle运行合约提供了本地的区块链环境,默认生成10个账户,每个账户初始余额为100ether。 也可以使用Ganache提供的图形化界面应用,需要修改配置连接的端口。
在一个新的控制台执行truffle migrate移植部署合约(或者在truffle develop控制台执行 migrate)。
使用truffle develop测试合约代码。
SimpleStorage.deployed().then(function(instance){return instance.get.call();}).then(function(value){return value.toNumber()})
// 0
SimpleStorage.deployed().then(function(instance){return instance.set(100);});
// 输出transaction信息
SimpleStorage.deployed().then(function(instance){return instance.get.call();}).then(function(value){return value.toNumber()});
// 100
使用truffle test 测试合约 使用truffle create test SimpleStorage新建或直接新建文件test/SimpleStorage.test.js。
const SimpleStorage = artifacts.require('SimpleStorage');
contract('SimpleStorage', function(accounts) {
it("should assert true", function(done) {
var simpleStorage = SimpleStorage.deployed();
var instance;
simpleStorage.then(res => {
instance = res;
return instance.get()
}).then(value => {
assert.equal('0', value.toNumber(), 'not equal 0')
}).then(() => {
instance.set(100)
}).then(() => {
return instance.get()
}).then(value => {
assert.equal('100', value.toNumber(), 'not equal 100')
})
done();
});
});
在新开的控制台里,输入
truffle test ./test/SimpleStorage.test.js
。使用remix测试合约 将使用truffle 开发的合约,放在remix里,可快速模拟合约的部署和调用。 remix提供了合约的编译运行环境,并可以在控制台看到合约每条交易的详细信息,如输入输出参数,签名后的方法data,交易hash等信息。支持调试。
使用compile detail,可以看到合约编译详情。包括bytecode,abi和使用web3.js快速部署的方法。
使用run来create 合约,控制台可查看创建合约的交易。
4.2.4 使用truffle unbox创建可交互合约应用
上面的步骤使用基本的truffle init创建了一个可编译部署调试的合约环境。 下面使用truffle unbox创建一个新的工程,unbox为我们提供了truffle工程模板,内置了一些合约应用交互的环境依赖。 可以在truffle boxes里查看官方提供的各种模板boxes。 下面使用的是react模板.
新建工程 truf-react
mkdir truf-react
cd truf-react
truffle unbox react
unbox过程会下载解压模板,执行npm install等操作。
配置项目的truffle.js
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
networks: {
development: {
host: '127.0.0.1',
port: '9545',
network_id: '*' // Match any network id
}
}
};
启动一个truffle develop
修改src/App.js
import React, { Component } from 'react'
import SimpleStorageContract from '../build/contracts/SimpleStorage.json'
import getWeb3 from './utils/getWeb3'
import './css/oswald.css'
import './css/open-sans.css'
import './css/pure-min.css'
import './App.css'
const contract = require('truffle-contract')
const simpleStorage = contract(SimpleStorageContract)
class App extends Component {
constructor(props) {
super(props)
this.state = {
storageValue: 0,
web3: null,
inputValue: 0,
address: null
}
this.changeValueHandle = this.changeValueHandle.bind(this)
this.setHandle = this.setHandle.bind(this)
}
componentWillMount() {
// Get network provider and web3 instance.
// See utils/getWeb3 for more info.
getWeb3
.then(results => {
this.setState({
web3: results.web3
})
// Instantiate contract once web3 provided.
this.instantiateContract()
})
.catch(() => {
console.log('Error finding web3.')
})
}
instantiateContract() {
/*
* SMART CONTRACT EXAMPLE
*
* Normally these functions would be called in the context of a
* state management library, but for convenience I've placed them here.
*/
this.simpleStorageSet(5)
}
changeValueHandle(event) {
this.setState({
inputValue: Number(event.target.value)
})
}
setHandle() {
this.simpleStorageSet(this.state.inputValue)
}
simpleStorageSet(x) {
simpleStorage.setProvider(this.state.web3.currentProvider)
// Declaring this for later so we can chain functions on SimpleStorage.
var simpleStorageInstance
// Get accounts.
this.state.web3.eth.getAccounts((error, accounts) => {
simpleStorage.deployed().then((instance) => {
simpleStorageInstance = instance
this.setState({ address: instance.address })
// Stores a given value, 5 by default.
return simpleStorageInstance.set(x, {from: accounts[0]})
}).then((result) => {
// Get the value from the contract to prove it worked.
return simpleStorageInstance.get.call(accounts[0])
}).then((result) => {
// Update state with the result.
return this.setState({ storageValue: result.c[0] })
})
})
}
render() {
return (
<div className="App">
<nav className="navbar pure-menu pure-menu-horizontal">
<a href="#" className="pure-menu-heading pure-menu-link">Truffle Box</a>
</nav>
<main className="container">
<div className="pure-g">
<div className="pure-u-1-1">
<h1>Good to Go!</h1>
<p>Your Truffle Box is installed and ready.</p>
<h2>Smart Contract Example</h2>
<p>If your contracts compiled and migrated successfully, below will show a stored value of 5 (by default).</p>
<p>Try changing the value stored on <strong>line 59</strong> of App.js.</p>
<p>The stored value is: {this.state.storageValue}</p>
<p>deployed contract address: {this.state.address}</p>
</div>
<div>
<input type="number" onChange={this.changeValueHandle}/>
<button onClick={this.setHandle}>set</button>
</div>
</div>
</main>
</div>
);
}
}
export default App
新增了合约set方法的调用。并展示了合约的address。
新打开一个控制台,执行 npm run start
通过set和输入框设置合约storedData的值。
在trufle develop里输入
//将xxx替换为address
SimpleStorage.at('xxxx').then(res => {return res.get()})
// 得到BigNUmber类型的返回值,c数组里的值即为设置的storedData的值。
4.2.5 使用浏览器插件 metamask 与区块链交互
参考 http://truffleframework.com/tutorials/pet-shop
4.2.6 合约开发参考文档与工具
solidity API
truffle文档
ganache 提供本地区块链环境的图形化界面
zeppelin-solidty 致力于安全的标准化的合约框架
web3.js 以太坊封装的与区块链交互的js
Smart Contract Security Best Practices(合约安全开发指南)