contract Migrations {
address public owner;// A function with the signature `last_completed_migration()`, returning a uint, is required.
uint public last_completed_migration;
modifier restricted(){if(msg.sender == owner) _
}
function Migrations(){
owner = msg.sender;}// A function with the signature `setCompleted(uint)` is required.
function setCompleted(uint completed) restricted {
last_completed_migration = completed;}
function upgrade(address new_address) restricted {
Migrations upgraded =Migrations(new_address);
upgraded.setCompleted(last_completed_migration);}}
module.exports =function(deployer, network){// Add demo data if we're not deploying to the live network.if(network !="live"){
deployer.exec("add_demo_data.js");}}
$ truffle migrate --network live
networks:{
development:{
host:"localhost",
port:8545,
network_id:"*"// match any network},
live:{
host:"178.25.19.88",// Random IP for example purposes (do not use)
port:80,
network_id:1,// Ethereum public network// optional config values// gas// gasPrice// from - default address to use for any transaction Truffle makes during migrations}}
在上面这个例子中,Truffle 会在 live 网络中进行移植,如果配置如上述配置示例的 Example 所指定的内容的话,是最终在以太坊网络上进行部署。
// Deploy a single contract without constructor arguments
deployer.deploy(A);// Deploy a single contract with constructor arguments
deployer.deploy(A, arg1, arg2,...);// Deploy multiple contracts, some with arguments and some without.// This is quicker than writing three `deployer.deploy()` statements as the deployer// can perform the deployment as a batched request.
deployer.deploy([[A, arg1, arg2,...],
B,[C, arg1]]);
// Deploy library LibA, then link LibA to contract B
deployer.deploy(LibA);
deployer.link(LibA, B);// Link LibA to many contracts
deployer.link(LibA,[B, C, D]);
(C)DEPLOYER.AUTOLINK(CONTRACT)
关联合约依赖的所有库,这需要所依赖的库已经部署,或在其前一步部署:
// Assume A depends on a LibB and LibC
deployer.deploy([LibB, LibC]);
deployer.autolink(A);
// Link *all* libraries to all available contracts
deployer.autolink();
(D)DEPLOYER.THEN(FUNCTION() {…})
Promise 语法糖,执行做生意的部署流程:
deployer.then(function(){// Create a new version of Areturn A.new();}).then(function(instance){// Set the new instance of A's address on B.
var b = B.deployed();return b.setA(instance.address);});
(E)DEPLOYER.EXEC(PATHTOFILE)
执行 truffle exec 做为部署的一部分:
// Run the script, relative to the migrations file.
deployer.exec("../path/to/file/demo_data.js");
五、构建应用
① 默认构建
Truffle 集成了默认的构建来方便使用,但也许不适合每个项目,所以也许需要其它的来打包应用。默认的构造目标是 web 应用,但也可以很容易的转变为其它的构造流程,比如适用于命令行或库的流程。
{"build":{// Copy ./app/index.html (right hand side) to ./build/index.html (left hand side)."index.html":"index.html",// Process all files in the array, concatenating them together// to create a resultant app.js"app.js":["javascripts/app.js"],// Process all files in the array, concatenating them together// to create a resultant app.css"app.css":["stylesheets/app.scss"],// Copy over the whole directory to the build destination."images/":"images/"}}
var account_one ="0x1234...";// an address
var account_two ="0xabcd...";// another address
var meta = MetaCoin.deployed();
meta.sendCoin(account_two,10,{from: account_one}).then(function(tx_id){// If this callback is called, the transaction was successfully processed.// Note that Ether Pudding takes care of watching the network and triggering// this callback.alert("Transaction successful!")}).catch(function(e){// There was an error! Handle it.})
var account_one ="0x1234...";// an address
var meta = MetaCoin.deployed();
meta.getBalance.call(account_one,{from: account_one}).then(function(balance){// If this callback is called, the call was successfully executed.// Note that this returns immediately without any waiting.// Let's print the return value.
console.log(balance.toNumber());}).catch(function(e){// There was an error! Handle it.})
分析:
必须通过 .call() 来显示的向以太坊网络表明,并不会持久化一些数据变化;
得到返回结果,而不是一个交易 ID,需要注意的是,以太坊网网络可以处理非常大的数字,我们被返回一个 BigNumber 对象,框架再将这个对象转化了一个 number 类型。
在上述的例子中将返回值转成了一个 number 类型,是因为例子中的返回值比较小,如果将一个 BigNumber 转换为比 javascript 支持的 number 最大整数都大,将会出现错误或不可预期的行为。
(C)捕捉事件(Catching Events)
合约可以触发事件,可以进行捕捉以进行更多的控制,事件 API 与 Web3 一样:
var meta = MetaCoin.deployed();
var transfers = meta.Transfer({fromBlock:"latest"});
transfers.watch(function(error, result){// This will catch all Transfer events, regardless of how they originated.if(error == null){
console.log(result.args);}}
MetaCoin.new().then(function(instance){// `instance` is a new instance of the abstraction.// If this callback is called, the deployment was successful.
console.log(instance.address);}).catch(function(e){// There was an error! Handle it.});
contract('MetaCoin',function(accounts){it("should put 10000 MetaCoin in the first account",function(){// Get a reference to the deployed MetaCoin contract, as a JS object.
var meta = MetaCoin.deployed();// Get the MetaCoin balance of the first account and assert that it's 10000.return meta.getBalance.call(accounts[0]).then(function(balance){
assert.equal(balance.valueOf(),10000,"10000 wasn't in the first account");});});});
networks:{"live":{
network_id:1,// Ethereum public network// optional config values// host - defaults to "localhost"// port - defaults to 8545// gas// gasPrice// from - default address to use for any transaction Truffle makes during migrations},"morden":{
network_id:2,// Official Ethereum test network
host:"178.25.19.88",// Random IP for example purposes (do not use)
port:80},"staging":{
network_id:1337// custom private network// use default rpc settings},"development":{
network_id:"default"}}
关于如何连接到以太坊客户端的一些细节,host 和 port 是需要,另外还需要一些其它的:
host:指向以太坊客户端的地址,本机开发时,一般为 localhost;
port:以太坊客户端接收请求的端口,默认是8545;
gas:部署时的 Gas 限制,默认是 4712388;
gasPrice:部署时的 Gas 价格,默认是 100000000000(100 Shannon);
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items,and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>--save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name:(truffle3) TruffleForTest
Sorry, name can no longer contain capital letters.
name:(truffle3) truffle3
version:(1.0.0)1.0.0
description: This is a sample project for integrate truffle 3.0 with nodejs.
entry point:(truffle.js) main.js
test command: truffle3
git repository:main.js
keywords: truffle3.0
author: TryBlockchain
license:(ISC)
About to write to /Users/TryBlockchain/develop/blockchain_workspace/truffle3/package.json:{"name":"truffle3","version":"1.0.0","description":"This is a sample project for integrate truffle 3.0 with nodejs.","main":"main.js","directories":{"test":"test"},"scripts":{"test":"truffle3"},"keywords":["truffle3.0"],"author":"TryBlockchain","license":"ISC"}
Is this ok?(yes) yes
如果不进行npm init初始化,就进行后续模块安装,会报如下错误:
$ npm install truffle-contract
/Users/TryBlockchain
└─┬ truffle-contract@1.1.10
├─┬ ethjs-abi@0.1.9
│ ├── bn.js@4.11.6
│ ├── js-sha3@0.5.5
│ └─┬ number-to-bn@1.7.0
│ ├── bn.js@4.11.6 deduped
│ └─┬ strip-hex-prefix@1.0.0
│ └── is-hex-prefixed@1.0.0
├── truffle-blockchain-utils@0.0.1
├─┬ truffle-contract-schema@0.0.5
│ └── crypto-js@3.1.9-1
└─┬ web3@0.16.0
└── bignumber.js@2.0.7(git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2)
npm WARN enoent ENOENT: no such file or directory, open '/Users/TryBlockchain/package.json'
npm WARN TryBlockchain No description
npm WARN TryBlockchain No repository field.
npm WARN TryBlockchain No README data
npm WARN TryBlockchain No license field.
由于没有包管理环境,所以对 package.json 的包依赖写入会失败,报错 npm WARN enoent ENOENT: no such file or directory, open ‘/Users/TryBlockchain/package.json’。要解决这个问题,需要使用 npm init 来初始化当前工程的包管理环境。
$ node main.js
/Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:4
var provider =new Web3.providers.HttpProvider("http://localhost:8545");^
ReferenceError: Web3 is not defined
at Object.<anonymous>(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:4:20)
at Module._compile(module.js:571:32)
at Object.Module._extensions..js(module.js:580:10)
at Module.load(module.js:488:32)
at tryModuleLoad(module.js:447:12)
at Function.Module._load(module.js:439:3)
at Module.runMain(module.js:605:10)
at run(bootstrap_NodeJS:420:7)
at startup(bootstrap_NodeJS:139:9)
at bootstrap_NodeJS:535:3
⑥ 创建自己的合约文件
(A)新增加测试合约
在 truffle3/contracts 目录下创建测试合约文件 Test.sol:
pragma solidity ^0.4.4;
contract Test{
function f()returns(string){return"method f()";}
function g()returns(string){return"method g()";}}
提供两个函数,f() 和 g(),分别返回用于说明它们是哪个函数的返回结果的字符串说明。
(B)增加 deploy 配置
修改 migrations/2_deploy_contracts.js 为如下:
var ConvertLib = artifacts.require("./ConvertLib.sol");
var MetaCoin = artifacts.require("./MetaCoin.sol");
var Test = artifacts.require("./Test.sol");module.exports =function(deployer){
deployer.deploy(ConvertLib);
deployer.link(ConvertLib, MetaCoin);
deployer.deploy(MetaCoin);
deployer.deploy(Test);};
上述代码主要增加两行,一行为 var Test = artifacts.require(“./Test.sol”); 声明一个新的合约文件实例并命名为 Test;增加的另一行内容 deployer.deploy(Test); 用于将 Test 进行部署。
var Web3 =require('web3');
var contract =require("truffle-contract");
var provider =new Web3.providers.HttpProvider("http://localhost:8545");//使用truffle-contract包的contract()方法//请务必使用你自己编译的.json文件内容
var Test =contract({"contract_name":"Test","abi":[{"constant":false,"inputs":[],"name":"f","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"g","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"}],"unlinked_binary":"0x606060405234610000575b6101ff806100196000396000f300606060405263ffffffff60e060020a60003504166326121ff0811461002f578063e2179b8e146100bc575b610000565b346100005761003c610149565b604080516020808252835181830152835191928392908301918501908083838215610082575b80518252602083111561008257601f199092019160209182019101610062565b505050905090810190601f1680156100ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b346100005761003c61018e565b604080516020808252835181830152835191928392908301918501908083838215610082575b80518252602083111561008257601f199092019160209182019101610062565b505050905090810190601f1680156100ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080516020818101835260009091528151808301909252600a82527f6d6574686f642066282900000000000000000000000000000000000000000000908201525b90565b604080516020818101835260009091528151808301909252600a82527f6d6574686f642067282900000000000000000000000000000000000000000000908201525b905600a165627a7a72305820c238bd4de6aa330fcc88946b9948bc265c7ac1408dc5c8b7ee6e648413ae540f0029","networks":{"1489826524891":{"events":{},"links":{},"address":"0x9db90af99faa32ed14dccfb19326e917efac456b","updated_at":1489827968151}},"schema_version":"0.0.5","updated_at":1489827968151});
Test.setProvider(provider);//没有默认地址,会报错//UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address//务必设置为自己的钱包地址,如果不知道,查看自己的客户端启动时,观察打印到控制台的地址
Test.defaults({
from :"0x299127d72e28cb92d09f856aaedeb139d1e7e74a"});
var instance;
Test.deployed().then(function(contractInstance){
instance = contractInstance;return instance.f.call();}).then(function(result){
console.log(result);return instance.g.call();}).then(function(result){
console.log(result);});
⑧ 集成示例
要在 NodeJS 中使用 Truffle,要先引入 web3:
var Web3 =require('web3');
var provider =new Web3.providers.HttpProvider("http://localhost:8545");// 省略了无关代码// 合约初始化
var Test =contract(/*合约JSON*/);// 设置连接
Test.setProvider(provider);
先通过 var Web3 = require(‘web3’); 引入依赖,并初始化一个实例 Web3,并为实例设置 HttpProvider。
$ node main.js
/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/lib/web3/contract.js:56
contract.abi.filter(function(json){^
TypeError: Cannot read property 'filter' of undefined
at addFunctionsToContract(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/li
b/web3/contract.js:56:17)
at ContractFactory.at(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/lib/we
b3/contract.js:255:5)
at TruffleContract.Contract(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:257:33)
at newTruffleContract(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:572:25)
at Function.at(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:390:22)
at Object.<anonymous>(/Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:54:6)
at Module._compile(module.js:571:32)
at Object.Module._extensions..js(module.js:580:10)
at Module.load(module.js:488:32)
at tryModuleLoad(module.js:447:12)