首页 > 分享 > 开发一个去中心化应用Dapp

开发一个去中心化应用Dapp

开发一个去中心化应用Dapp-宠物领养

2018.02.09 14:14:07字数 969阅读 1,596

1. 参考资料

http://truffleframework.com/tutorials/pet-shop
这是一个使用以太坊开发的完整的去中心化应用(Dapp),出自tuffle suite。
Pete有一个宠物店,养了16只宠物,他想开发一个去中心化应用,让大家来领养宠物。
应用效果如下:

屏幕快照 2018-02-09 上午11.00.25 (2).png

2. 环境搭建

安装nodejs 安装truffle 安装ganache-cli 安装MetaMask

3. 创建项目

感谢truffle unbox,你不必从头开始创建项目。

这一步需要稍等一会,truffle会自动下载pet-shop项目,项目目录如下:


屏幕快照 2018-02-09 上午11.05.31.png

contracts 存放智能合约; migrations 存放部署脚本; test 存放测试用例; truffle.js 配置文件,例如区块链地址和端口;

4. 编写智能合约

在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在数组长度内 adopters[petId] = msg.sender; // 保存调用这地址 return petId; } // 返回领养者 function getAdopters() public view returns (address[16]) { return adopters; } }

5. 编译智能合约

6. 启动以太坊客户端

yangang:~ yangang$ ganache-cli Ganache CLI v6.0.3 (ganache-core: 2.0.2) Available Accounts ================== (0) 0xebbc700bb15e3aa969f9d8ece9090aeb262cbf6e (1) 0x940ead554300f8b0a40530f6f77b138d24b9359b (2) 0xf47f7cd72e1377a6220bf512f5690d1027313dee (3) 0x1c22e4df38807b47f26ad1f25503c23947e9e7e1 (4) 0xb8cf54c3ebdf06ae887222c23930bad155453891 (5) 0xc8232b9bc251ab9c393071747616e0a831b143ec (6) 0x01c05db44cfbb7bf7b5671cc0e197e72607f0166 (7) 0xa08e0b2855556167afd44c63c6429c8372a6cf01 (8) 0x18ca58212d87cca4842471475ada5d78183d7fdb (9) 0xcb465d0d7a7b067c7b0c8272078710bc4937d134 Private Keys ================== (0) 0eb629b963b89ef28272b68437cf65f52a92a963188fa41ed86578158388f0f5 (1) a9c3f1332bd3d7b42b45c6aec59f2d966478c831ca4e71e0ebd251d248cfecf4 (2) b50d1f99eca8a322c2968265a48017be275fcf1f8e9f6ff382b9d1d4c4495443 (3) 6a14cbcb204156880cf663557cf0f919aa297ddf9bed83afc7c4bfe2a1aa5aef (4) af1c52412f92380d7536324106875e0f30106fa9e50da3e0336eef17779da3ca (5) 13d45f5707aab605bc42c411aa455c77b7346371609b3606bf001a6359a3a37c (6) 3763c2a208e5c690a187e8228344a7ff6f25494ed5af907f0c14660074f9484d (7) 230a4a6beb106e20f5204b14a3ce293e240ffcdf58c8c349ea297af446724c43 (8) 80410ba728a87b877921a8614cd802e5f06c638bf38d3df2b774bc2ecb969ea8 (9) 0f0b78f8b517f065e8a57d4ddcfbc6b3dcfa480f70a51bdd260d7cf530a543be HD Wallet ================== Mnemonic: powder omit enforce twelve student rigid large caution eternal sibling pepper human Base HD Path: m/44'/60'/0'/0/{account_index} Listening on localhost:8545

注意这里的MnemonicAccounts,后面MetaMask需要用到。

7. 部署合约(migrate)

在migrations目录下,创建一个部署脚本2_deploy_contracts.js:

var Adoption = artifacts.require("Adoption"); module.exports = function(deployer) { deployer.deploy(Adoption); };

注意这里的写法,artifacts.require("Adoption")的参数为合约名称。
此外,为什么部署脚本要以数字开头呢?这是truffle部署时用的ID。
接下来执行部署命令:

yangang:migrations yangang$ truffle migrate --reset Using network 'development'. Running migration: 1_initial_migration.js Replacing Migrations... ... 0xb61538c615d6268399b938d9d143ae6b941f5042047a352f282000e28d477968 Migrations: 0x359208970726992a5c8fc91fd73f4bd5e85ec797 Saving successful migration to network... ... 0x2d647da26ab9cec9023f9f6cf472a88d4b6c80589c5411dcd0625008f628c46c Saving artifacts... Running migration: 2_deploy_contracts.js Replacing Adoption... ... 0x8794814a4af225df5034f55ac34b9ec93fb803286b5b12c152b151881b9d389b Adoption: 0x3dd3623e515a405921f0479205cfa41596efe755 Saving successful migration to network... ... 0x58fac81009ebbe60969e4f13ff69bc63db5649abd1161e36a7a15613969442b4 Saving artifacts..

使用--reset来强制重编译并部署所有合约。

8. 测试合约

在test目录下,新建测试案例TestAdoption.sol

pragma solidity ^0.4.17; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Adoption.sol"; contract TestAdoption { Adoption adoption = Adoption(DeployedAddresses.Adoption()); // Testing the adopt() function function testUserCanAdoptPet() public { uint returnedId = adoption.adopt(8); uint expected = 8; Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded."); } // Testing retrieval of a single pet's owner function testGetAdopterAddressByPetId() public { // Expected owner is this contract address expected = this; address adopter = adoption.adopters(8); Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded."); } // Testing retrieval of all pet owners function testGetAdopterAddressByPetIdInArray() public { // Expected owner is this contract address expected = this; // Store adopters in memory rather than contract's storage address[16] memory adopters = adoption.getAdopters(); Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded."); } }

接下来,运行测试案例:

yangang:test yangang$ truffle test Using network 'development'. Compiling ./contracts/Adoption.sol... Compiling ./test/TestAdoption.sol... Compiling truffle/Assert.sol... Compiling truffle/DeployedAddresses.sol... TestAdoption ✓ testUserCanAdoptPet (98ms) ✓ testGetAdopterAddressByPetId (62ms) ✓ testGetAdopterAddressByPetIdInArray (90ms) 3 passing (781ms)

9. 创建UI和智能合约交互

在pet-shop项目中,已经包含了前端代码,在src目录下。
我们主要是修改app.js:

App = { web3Provider: null, contracts: {}, init: function() { // Load pets. $.getJSON('../pets.json', function(data) { var petsRow = $('#petsRow'); var petTemplate = $('#petTemplate'); for (i = 0; i < data.length; i ++) { petTemplate.find('.panel-title').text(data[i].name); petTemplate.find('img').attr('src', data[i].picture); petTemplate.find('.pet-breed').text(data[i].breed); petTemplate.find('.pet-age').text(data[i].age); petTemplate.find('.pet-location').text(data[i].location); petTemplate.find('.btn-adopt').attr('data-id', data[i].id); petsRow.append(petTemplate.html()); } }); return App.initWeb3(); }, initWeb3: function() { /* * Replace me... */ // Is there an injected web3 instance? if (typeof web3 !== 'undefined') { App.web3Provider = web3.currentProvider; } else { // If no injected web3 instance is detected, fall back to Ganache App.web3Provider = new Web3.providers.HttpProvider('http://localhost:8545'); } web3 = new Web3(App.web3Provider); return App.initContract(); }, initContract: function() { /* * Replace me... */ // 加载Adoption.json,保存了Adoption的ABI(接口说明)信息及部署后的网络(地址)信息,它在编译合约的时候生成ABI,在部署的时候追加网络信息 $.getJSON('Adoption.json', function(data) { // 用Adoption.json数据创建一个可交互的TruffleContract合约实例。 var AdoptionArtifact = data; 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(); }, bindEvents: function() { $(document).on('click', '.btn-adopt', App.handleAdopt); }, markAdopted: function(adopters, account) { /* * Replace me... */ 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') { console.log('hahahah'); console.log(adopters[i]); $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true); } } }).catch(function(err) { console.log(err.message); }); }, handleAdopt: function(event) { event.preventDefault(); var petId = parseInt($(event.target).data('id')); /* * Replace me... */ var adoptionInstance; // 获取用户账号 web3.eth.getAccounts(function(error, accounts) { if (error) { console.log(error); } 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); }); }); } }; $(function() { $(window).load(function() { App.init(); }); });

9.1 实例化合约

Adoption部署成功后,在build/contracts目录下会生成Adoption.json文件,记录合约部署信息;
initContract函数读取Adoption.json文件,创建一个合约实例contracts.Adoption.
markAdopted函数使用合约实例,调用getAdopters()方法,获取所有领养者列表,回到页面上,把对应宠物的领养按钮置灰,改名为Success。


屏幕快照 2018-02-09 上午11.41.58.png

9.2 处理领养

handleAdopt函数处理领养按钮,首先获取区块链用户账号,然后调用合约实例的adopt(petId)方法,领养宠物。

10. 在浏览器中访问区块链

MetaMask是一款插件形式的以太坊客户端,我使用的是firefox浏览器。
MetaMask登录界面:


屏幕快照 2018-02-09 下午1.33.30.png

选择可供连接的网络:


屏幕快照 2018-02-09 下午1.35.47.png


因为ganache-cli的监听端口为8545,所以我们选择“Localhost 8545”:
点击“Restore from seed phrase”,

屏幕快照 2018-02-09 下午1.40.04.png

注意,"Wallet Seed"框中填入ganache-cli的Mnemonic:

HD Wallet ================== Mnemonic: powder omit enforce twelve student rigid large caution eternal sibling pepper human

设置密码,确认即可,下次登录直接使用该密码。


屏幕快照 2018-02-09 下午1.44.04.png

登录后,能看到用户及相关交易信息,默认用户名为Account 1,查看该用户地址:

0xebBc700bb15e3aA969f9D8ECe9090aEb262CBf6e

与ganache-cli的用户列表相比:

Available Accounts ================== (0) 0xebbc700bb15e3aa969f9d8ece9090aeb262cbf6e (1) 0x940ead554300f8b0a40530f6f77b138d24b9359b (2) 0xf47f7cd72e1377a6220bf512f5690d1027313dee (3) 0x1c22e4df38807b47f26ad1f25503c23947e9e7e1 (4) 0xb8cf54c3ebdf06ae887222c23930bad155453891 (5) 0xc8232b9bc251ab9c393071747616e0a831b143ec (6) 0x01c05db44cfbb7bf7b5671cc0e197e72607f0166 (7) 0xa08e0b2855556167afd44c63c6429c8372a6cf01 (8) 0x18ca58212d87cca4842471475ada5d78183d7fdb (9) 0xcb465d0d7a7b067c7b0c8272078710bc4937d134

发现什么了吗?其实就是第一个用户。

11. 安装和配置lite-server

接下来需要本地的web服务器提供服务的访问,Truffle Box pet-shop里面,提供了一个lite-server可以直接使用,我们看看它是如何工作的。
bs-config.json指示了lite-server的工作目录:

{ "server": { "baseDir": ["./src", "./build/contracts"] } }

与此同时,在pckage.json的scriptes中添加了dev命令:

"scripts": { "dev": "lite-server", "test": "echo "Error: no test specified" && exit 1" },

这样,当运行npm run dev的时候,就会启动lite-server.

12. 启动服务

会自动打开浏览器,显示我们的dapp:


屏幕快照 2018-02-09 下午1.54.01 (2).png

现在领养第四只宠物Melissa看看,当我们点击Adopt时,MetaMask会提示我们交易的确认:


屏幕快照 2018-02-09 下午1.55.21.png


注意:MetaMask和dapp必须在同一个浏览器中哦,否则不会提示的。
点击submit确认后,如图所示,交易29执行成功了。

屏幕快照 2018-02-09 下午1.57.33.png

刷新页面,我们可以发现,Melissa已经被领养了。


屏幕快照 2018-02-09 下午1.58.57 (2).png

13. 总结

到此为止,我们已经完成了一个简单的dapp,恭喜自己吧。
后续还有其他问题,例如如何控制用户权限,如何处理并发领养等等。

最后编辑于

:2018.02.09 14:20:39

更多精彩内容,就在简书APP

"小礼物走一走,来简书关注我"

还没有人赞赏,支持一下

序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...

沈念sama阅读 199,636评论 5赞 468

序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...

文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...

文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...

正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...

茶点故事阅读 62,665评论 5赞 359

文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...

那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...

文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...

序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...

正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...

茶点故事阅读 35,274评论 2赞 317

正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...

茶点故事阅读 37,319评论 1赞 329

序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...

正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...

茶点故事阅读 38,599评论 3赞 303

文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...

文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...

我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...

正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...

茶点故事阅读 41,885评论 2赞 341

推荐阅读更多精彩内容

最新内容会更新在主站深入浅出区块链社区原文链接:一步步教你开发、部署第一个去中心化应用(Dapp) - 宠物商店 ...

一、Solidity 语言 Solidity 是一种智能合约高级语言,运行在 Ethereum 虚拟机(EVM:E...

「半梦半醒时,你是确确实实存在过」 停住了,不能回头,别再找过去谁错谁对,让我看清你这一刻的容颜印在心里,我记住了...

喵记几阅读 329评论 2赞 0

今天不忙 下班比较早 组织了一下 一起去发宣传册 提高进厂台次 只要进店了 就有拓展业务的机会

1.环境搭建 在场景中创建Plane,添加AudioSource组件和Play脚本.并创建Resources文件夹...

Jens丶阅读 5,298评论 12赞 12

相关知识

开发一个去中心化应用Dapp
Truffle & Web3.js 教程:教你开发、部署第一个去中心化应用(Dapp)
区块链DAPP
开发第一个基于以太坊的dapp
Web3优秀案例收集整理(附带源码):80+ 项目、创意和案例等待你的探索
第十二课 从宠物商店案例看DAPP架构和WEB3.JS交互接口
【精品】边黎安大神陪你一起学dapp以太坊 宠物狗领养 免费大神指导
区块链100讲:从宠物商店案例看DAPP架构和WEB3.JS交互接口
区块链案例实践报告
Vitalik 出席的基辅 Web3 黑客松获胜项目一览

网址: 开发一个去中心化应用Dapp https://m.mcbbbk.com/newsview429059.html

所属分类:萌宠日常
上一篇: 三门峡宠物赠送/领养电话
下一篇: 宠物领养公益单模板