truffle的宠物商店是一个了解以太坊开发的一个很不错的例子.
跟着官方提供的demo与教程,可以完整的感受一下整个流程的开发.
Ganache
为了环境需要,并且快速的在本地搭建一个私有链环境.
truffle推出了一个可视化私有链客户端:
Ganache下载地址
下载之后运行,你会看到这样一个界面:

初始化你的项目
首先我们新建一个目录,并且初始化一下项目
$ mkdir pet-shop $ cd pet-shop $ truffle unbox pet-shop
|
项目目录结构
这里只列出了重要的目录与文件
├── bs-config.json ├── contracts //合约目录 │ └── Migrations.sol //合约文件 ├── migrations // 部署脚本 │ └── 1_initial_migration.js ├── package-lock.json ├── package.json ├── src // 前端代码目录 ├── test // 测试代码目录 └── truffle.js // truffle配置文件
|
编写智能合约
在contracts/目录中,创建一个Adoption.sol文件
文件内容:
pragma solidity ^0.4.17;
contract Adoption {
address[16] public adopters; // 声明一个地址变量,用于保存领养者地址
// 领养宠物 function adopt(uint petId) public returns (uint) { require(petId >= 0 && petId <= 15); // 确保宠物id正确,为0到15之间, // 如果不符合条件就会回滚 //msg.sender 为调用这个函数的人的地址 adopters[petId] = msg.sender; // 保存调用这地址 return petId; }
// 返回领养者 function getAdopters() public view returns (address[16]) { return adopters; }
}
|
编译你的智能合约
$ truffle compile
//输出 Compiling ./contracts/Adoption.sol... Writing artifacts to ./build/contracts
|
这样你就会发现你的项目多了一个build文件夹,
里面存放这里刚刚写好的智能合约编译完成的json文件
部署你的智能合约
你的智能合约写好了,你可以暂且理解为你的后台代码写好了.要部署起来便于前端调用.
在你的migrations/目录新建一个部署脚本:2_deploy_contracts.js
var Adoption = artifacts.require("Adoption");
module.exports = function(deployer) { deployer.deploy(Adoption); };
|
打开刚刚下载的Ganache, Ganache会启动一个私有链.
我们的智能合约就是要部署在这个私有链上.
确认项目录根目录的truffle.js
module.exports = { networks: { development: { host: "127.0.0.1", port: 7545, //确保端口地址,是否与私有链地址一致,如果不一致请保持一致 network_id: "*" // Match any network id } } };
|
执行以下命令,部署合约:
truffle migrate
# 输出 Using network 'develop'.
Running migration: 1_initial_migration.js Deploying Migrations... ... 0x3076b7dac65afc44ec51508bf6f2b6894f833f0f9560ecad2d6d41ed98a4679f Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 Saving successful migration to network... ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956 Saving artifacts... Running migration: 2_deploy_contracts.js Deploying Adoption... ... 0x2c6ab4471c225b5473f2079ee42ca1356007e51d5bb57eb80bfeb406acc35cd4 Adoption: 0x345ca3e014aaf5dca488057592ee47305d9b3e10 Saving successful migration to network... ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0 Saving artifacts...
|
重新打开Ganache,你会发现区块链的状态发生了变化,多了4个区块.
OK,部署完毕

前端与智能合约的交互
好,智能合约我们已经部署好了.接下来我们就要开始我们的javascript部分了
打开 src/js/app.js
初始化web3
web3是一个前端与以太坊通信的库,所有调用智能合约的操作,我们基于web3来实现.
我们在app.js里找到initWeb3方法,为其添加以下代码:
initWeb3: function() { // 判断是否有全局web3对象,一般装了MetaMask这种钱包就会有全局的web3对象 if (typeof web3 !== 'undefined') { // 如果有,就直接使用 App.web3Provider = web3.currentProvider; } else { // 如果没有全局的web3对象,就直接在本地初始化一个 App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545'); } web3 = new Web3(App.web3Provider);
return App.initContract(); }
|
实例化智能合约
找到initContract方法部分,添加以下代码:
initContract: function() { //加载我们的之前写好的智能合约 $.getJSON('Adoption.json', function(data) { // 用Adoption.json数据创建一个可交互的TruffleContract合约实例。 var AdoptionArtifact = data; //TruffleContract 为该项目的全局方法,使用的是 truffle-contract这个库 //如果在其他项目,你可以直接npm i truffle-contract --save 来安装这个库 //用于实例化合约 App.contracts.Adoption = TruffleContract(AdoptionArtifact);
// Set the provider for our contract App.contracts.Adoption.setProvider(App.web3Provider);
// Use our contract to retrieve and mark the adopted pets return App.markAdopted(); }); return App.bindEvents(); }
|
领养部分
handleAdopt方法部分,添加以下代码:
handleAdopt: function(event) { event.preventDefault(); //dom里获取到宠物的id var petId = parseInt($(event.target).data('id'));
var adoptionInstance;
// 获取用户账号 web3.eth.getAccounts(function(error, accounts) { if (error) { console.log(error); } //获取用户,如果装了钱包只会返回长度只有1的数组,如果没有装钱包,会返回所有用户的地址 var account = accounts[0]; //调用智能合约 App.contracts.Adoption.deployed().then(function(instance) { adoptionInstance = instance;
// 发送交易领养宠物 return adoptionInstance.adopt(petId, {from: account}); }).then(function(result) { return App.markAdopted(); }).catch(function(err) { console.log(err.message); }); }); }
|
找到 markAdopted方法,添加以下代码:
markAdopted: function(adopters, account) { var adoptionInstance; //调用合约的方法 App.contracts.Adoption.deployed().then(function(instance) { adoptionInstance = instance;
// 调用合约的getAdopters(), 用call读取信息不用消耗gas return adoptionInstance.getAdopters.call(); }).then(function(adopters) { for (i = 0; i < adopters.length; i++) { if (adopters[i] !== '0x0000000000000000000000000000000000000000') { $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true); } } }).catch(function(err) { console.log(err.message); }); }
|
启动服务
好了,所有代码我们都已经填充完毕,启动我们的项目,开始领养你喜欢的宠物吧