1.github项目下载
结构:
目录结构简单说明如下:
app/ - 你的应用文件运行的默认目录。这里面包括推荐的javascript文件和css样式文件目录,但你可以完全决定如何使用这些目录。
contract/ - Truffle默认的合约文件存放地址。
migrations/ - 存放发布脚本文件
test/ - 用来测试应用和合约的测试文件
truffle.js - Truffle的配置文件
详细说明:配置说明
2.放入自己的合约
删除./contract目录下的自带demo合约,切记不要删除./contract/Migrations.sol合约,它是Truffle用来帮助部署的。
在./contract目录下创建一个自己的合约文件Greeter.sol。
pragma solidity ^0.4.0;
contract Greeter
{
address creator;
string greeting;
function Greeter(string _greeting) public
{
creator = msg.sender;
greeting = _greeting;
}
function greet() constant returns (string)
{
return greeting;
}
function setGreeting(string _newgreeting)
{
greeting = _newgreeting;
}
/**********
Standard kill() function to recover funds
**********/
function kill()
{
if (msg.sender == creator)
suicide(creator); // kills this contract and sends remaining funds back to creator
}
}
代码来自fiveDogIt的一段入门代码05_greeter.sol。
3.修改发布脚本
将./migrations/2_deploy_contracts.js下的内容由:
module.exports = function(deployer) {
deployer.deploy(ConvertLib);
deployer.autolink();
deployer.deploy(MetaCoin);
};
修改为:
module.exports = function(deployer) {
deployer.deploy(Greeter);
};
目的是去掉原有自带的Demo部署流程,修改为要部署的合约。修改完后,记得保存,不然发布时会报错,找不到相关合约。详细发布流程参考:部署(migrate)
4. 编译
进入到工程根目录./webpack-box-master目录下,进行编译:
C:\Users\LiYing\Desktop\区块链\webpack-box-master>truffle.cmd compile
Compiling .\contracts\ConvertLib.sol...
Compiling .\contracts\Greeter.sol...
Compiling .\contracts\MetaCoin.sol...
Compiling .\contracts\Migrations.sol...
如果出现警告,可忽略.不是err就行.
5.启动客户端
如果你已经安装了ganache-cli,那么直接在webpack-box-master下:
C:\Users\LiYing\Desktop\区块链\webpack-box-master>ganache-cli
否则先安装
npm install -g ganache-cli truffle
参考文档1
参考文档2
如果出现Error: Cannot find module ‘babel-register’,点击此处
可以看到ganache-cli启动后自动建立了10个帐号(Accounts),与每个帐号对应的私钥(Private Key)。每个帐号中都有100个测试用的以太币(Ether)。要注意ganache-cli仅运行在內存中,因此每次重开时都会回到全新的状态。
建立项目
开启另一个终端窗口,输入以下命令以建立项目:
C:\Users\LiYing\Desktop\区块链>mkdir SmartContractDemo
C:\Users\LiYing\Desktop\区块链>cd SmartContractDemo
C:\Users\LiYing\Desktop\区块链\SmartContractDemo>mkdir HelloWord
C:\Users\LiYing\Desktop\区块链\SmartContractDemo>cd HelloWord
C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
目录结构:
/contracts:存放智能合约原始代码的地方,可以看到里面已经有一个sol文件,我们开发的HelloWorld.sol文件就存放在这个文件夹。
type nul>HelloWorld.sol
HelloWorld.sol文件內容如下:
pragma solidity ^0.4.17;
contract HelloWorld {
function sayHello() returns (string) {
return "HelloWorld";
}
}
讲解
pragma solidity ^0.4.17;
第一行指的是目前使用的solidity版本,不同版本的solidity可能会编译出不同的bytecode。^代表兼容solidity“0.4.17 ~ 0.4.9的版本。
contract HelloWorld {
...
}
contract关键字类似于其他语言中较常见的class。因为solidity是专为智能合约(Contact)设计的语言,声明contract后即内置了开发智能合约所需的功能。也可以把这句理解为class HelloWorld extends Contract。
function sayHello() returns (string) {
return "HelloWorld";
}
函数的结构与其他程序类似,但如果有传入的参数或回传值,需要指定参数或回传值的类型(type)。
/migrations:这是 Truffle用来部署智能合约的功能,待会儿我们会新建一个类似1_initial_migration.js的文件来部署 HelloWorld.sol。
type nul>1_initial_migration.js
/test:测试智能合约的代码放在这里,支持js 与 sol 测试。
根目录下truffle.js/truffle-config.js: Truffle 的配置文件,需要配置要连接的以太坊网络
配置truffle.js文件
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // Match any network id
}
}
};
编译
现在执行truffle compile命令,我们可以将HelloWorld.sol原始码编译成Ethereum bytecode。
C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle.cmd compile
Compiling .\contracts\HelloWorld.sol...
Compiling .\contracts\Migrations.sol...
Warning暂时忽略,编译成功后,会在HelloWorld文件夹下面的build/contracts文件夹下面看见HelloWorld.json文件。
部署
truffle框架中提供了方便部署合约的脚本。新建migrations/2_deploy_contracts.js文件(脚本使用Javascript编写),将内容修改如下:
var HelloWorld = artifacts.require("./HelloWorld.sol");
module.exports = function(deployer) {
deployer.deploy(HelloWorld);
};
使用artifacts.require语句来取得准备部署的合约。使用deployer.deploy语句将合约部署到区块链上。这边HelloWorld是contract的名称而不是文件名。因此可以用此语法读入任一.sol文件中的任一合约。
执行truffle migrate命令:
再次说下,如果执行truffle migrate会打开js文件,那就加上.cmd后缀如下图
合约已经部署到ganache-cli中。切换到ganache-cli窗口,可以看到ganache-cli有反应了。
与合约互动
truffle提供命令行工具,执行truffle console命令后,可用Javascript来和刚刚部署的合约互动。
C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle console
C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle.cmd console
truffle(development)> let contract
undefined
truffle(development)> HelloWorld.deployed().then(instance => contract = instance
)
TruffleContract {
constructor:
{ [Function: TruffleContract]
_static_methods:
{ setProvider: [Function: setProvider],
new: [Function: new],
at: [Function: at],
deployed: [Function: deployed],
defaults: [Function: defaults],
hasNetwork: [Function: hasNetwork],
isDeployed: [Function: isDeployed],
detectNetwork: [Function: detectNetwork],
setNetwork: [Function: setNetwork],
resetAddress: [Function: resetAddress],
link: [Function: link],
clone: [Function: clone],
addProp: [Function: addProp],
toJSON: [Function: toJSON] },
_properties:
{ contract_name: [Object],
contractName: [Object],
abi: [Object],
network: [Function: network],
networks: [Function: networks],
address: [Object],
transactionHash: [Object],
links: [Function: links],
events: [Function: events],
binary: [Function: binary],
deployedBinary: [Function: deployedBinary],
unlinked_binary: [Object],
bytecode: [Object],
deployedBytecode: [Object],
sourceMap: [Object],
deployedSourceMap: [Object],
source: [Object],
sourcePath: [Object],
legacyAST: [Object],
ast: [Object],
compiler: [Object],
schema_version: [Function: schema_version],
schemaVersion: [Function: schemaVersion],
updated_at: [Function: updated_at],
updatedAt: [Function: updatedAt] },
_property_values: {},
_json:
{ contractName: 'HelloWorld',
abi: [Array],
bytecode:
'0x608060405234801561001057600080fd5b5061013f806100206000396000f3006080
60405260043610610041576000357c01000000000000000000000000000000000000000000000000
00000000900463ffffffff168063ef5fb05b14610046575b600080fd5b34801561005257600080fd
5b5061005b6100d6565b604051808060200182810382528381815181526020019150805190602001
9080838360005b8381101561009b578082015181840152602081019050610080565b505050509050
90810190601f1680156100c85780820380516001836020036101000a031916815260200191505b50
9250505060405180910390f35b60606040805190810160405280600a81526020017f48656c6c6f57
6f726c64000000000000000000000000000000000000000000008152509050905600a165627a7a72
305820232cfce6518204d3739a689f5b59477beb3c3188f7f57b5ae002f164390df7330029',
deployedBytecode:
'0x608060405260043610610041576000357c0100000000000000000000000000000000
000000000000000000000000900463ffffffff168063ef5fb05b14610046575b600080fd5b348015
61005257600080fd5b5061005b6100d6565b60405180806020018281038252838181518152602001
91508051906020019080838360005b8381101561009b578082015181840152602081019050610080
565b50505050905090810190601f1680156100c85780820380516001836020036101000a03191681
5260200191505b509250505060405180910390f35b60606040805190810160405280600a81526020
017f48656c6c6f576f726c6400000000000000000000000000000000000000000000815250905090
5600a165627a7a72305820232cfce6518204d3739a689f5b59477beb3c3188f7f57b5ae002f16439
0df7330029',
sourceMap: '25:93:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:93:0;;;;;;;',
deployedSourceMap:
'25:93:0:-;;;;;;;;;;;;;;;;;;;;;;;;49:67;;8:9:-1;5:2;;;30:1;27;20:12;5:2
;49:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;
;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:1
4;49:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78:6;92:19;;;;;;;;;;;;
;;;;;;;;49:67;:::o',
source:
'pragma solidity ^0.4.17;\ncontract HelloWorld {\n function sayHello()
returns (string) {\n return "HelloWorld";\n }\n}',
sourcePath:
'C:\\Users\\LiYing\\Desktop\\区块链\\SmartContractDemo\\HelloWord\\cont
racts\\HelloWorld.sol',
ast: [Object],
legacyAST: [Object],
compiler: [Object],
networks: [Object],
schemaVersion: '2.0.1',
updatedAt: '2018-08-30T13:57:12.712Z' },
setProvider: [Function: bound setProvider],
new: [Function: bound new],
at: [Function: bound at],
deployed: [Function: bound deployed],
defaults: [Function: bound defaults],
hasNetwork: [Function: bound hasNetwork],
isDeployed: [Function: bound isDeployed],
detectNetwork: [Function: bound detectNetwork],
setNetwork: [Function: bound setNetwork],
resetAddress: [Function: bound resetAddress],
link: [Function: bound link],
clone: [Function: bound clone],
addProp: [Function: bound addProp],
toJSON: [Function: bound toJSON],
web3:
Web3 {
_requestManager: [RequestManager],
currentProvider: [Provider],
eth: [Eth],
db: [DB],
shh: [Shh],
net: [Net],
personal: [Personal],
bzz: [Swarm],
settings: [Settings],
version: [Object],
providers: [Object],
_extend: [Function] },
class_defaults:
{ from: '0x1a1cf647a974c7baa2156af94a415adffb9a8062',
gas: 6721975,
gasPrice: 100000000000 },
currentProvider:
HttpProvider {
host: 'http://127.0.0.1:8545',
timeout: 0,
user: undefined,
password: undefined,
headers: undefined,
send: [Function],
sendAsync: [Function],
_alreadyWrapped: true },
network_id: '1535636698643' },
abi:
[ { constant: false,
inputs: [],
name: 'sayHello',
outputs: [Array],
payable: false,
stateMutability: 'nonpayable',
type: 'function' } ],
contract:
Contract {
_eth:
Eth {
_requestManager: [RequestManager],
getBalance: [Function],
getStorageAt: [Function],
getCode: [Function],
getBlock: [Function],
getUncle: [Function],
getCompilers: [Function],
getBlockTransactionCount: [Function],
getBlockUncleCount: [Function],
getTransaction: [Function],
getTransactionFromBlock: [Function],
getTransactionReceipt: [Function],
getTransactionCount: [Function],
call: [Function],
estimateGas: [Function],
sendRawTransaction: [Function],
signTransaction: [Function],
sendTransaction: [Function],
sign: [Function],
compile: [Object],
submitWork: [Function],
getWork: [Function],
coinbase: [Getter],
getCoinbase: [Function],
mining: [Getter],
getMining: [Function],
hashrate: [Getter],
getHashrate: [Function],
syncing: [Getter],
getSyncing: [Function],
gasPrice: [Getter],
getGasPrice: [Function],
accounts: [Getter],
getAccounts: [Function],
blockNumber: [Getter],
getBlockNumber: [Function],
protocolVersion: [Getter],
getProtocolVersion: [Function],
iban: [Function],
sendIBANTransaction: [Function: bound transfer] },
transactionHash: null,
address: '0x9fac2e57170b5b700b0e3e1f8fd16cc5980eee87',
abi: [ [Object] ],
sayHello:
{ [Function: bound ]
request: [Function: bound ],
call: [Function: bound ],
sendTransaction: [Function: bound ],
estimateGas: [Function: bound ],
getData: [Function: bound ],
'': [Circular] },
allEvents: [Function: bound ] },
sayHello:
{ [Function]
call: [Function],
sendTransaction: [Function],
request: [Function: bound ],
estimateGas: [Function] },
sendTransaction: [Function],
send: [Function],
allEvents: [Function: bound ],
address: '0x9fac2e57170b5b700b0e3e1f8fd16cc5980eee87',
transactionHash: null }
truffle(development)>
truffle(development)> contract.sayHello.call()
'HelloWorld'
讲解
HelloWorld.deployed().then(instance => contract = instance)
truffle console中预载了truffle-contract函数库,以方便操作部署到区块链上的合约。
这边使用HelloWorld.deployed().then语句来取得HelloWorld合约的Instance(实例),并存到contract变量中,以方便后续的调用。
上面用的是Javascript ES6+的语法,这句也可以写成:
HelloWorld.deployed().then(instance => {contract = instance});
还可以用 ES5 的写法(直接copy请去掉换行符):
HelloWorld.deployed().then(function(instance) {
hello = instance;
});
truffle(development)> contract.sayHello.call()
'Hello World'
我们已写好并部署完成了第一个智能合约,也验证了合约确实可以运作
加入新方法
我们在HelloWorld.sol中再加入一个echo方法,echo方法接受输入一个参数,并回传传送的参数。
function echo(string name) constant returns (string) {
return name;
}
新的echo方法中传入了一个name参数。我们也为echo方法加入一个constant声明,表示调用这个方法并不会改变区块链的状态。如此一来,透过truffle-contract来调用此方法时,会自动选用call来呼叫,也不需要额外提供 gas。
由于更新了合约内容,我们需要先重新新编译一次,将编译结果部署到ganache-cli上,再透过truffle console执行看看结果。
待续…