上两篇文章:
区块链学习(一) Ubuntu 下编译 ETH 客户端
区块链学习(二)搭建基于go-ethereum的以太坊的私有链环境

本次配置:

虚拟机:Vmware 15.1
系统:Ubuntu 16.04 LTS
nodejs:10.22.1

1 安装与环境配置

管理员模式

sudo su

升级所有包

apt-get update && sudo apt-get -y upgrade
apt-get -y install curl git vim build-essential

安装 npm

apt install npm

修改 npm 镜像源

npm config set registry http://registry.npm.taobao.org

安装依赖环境

apt-get install g++
apt-get install libssl-dev
apt-get install solc

安装 nodejs 10.22.1 (低于该版本可能无法安装)

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs

安装 web3

npm install web3

安装 ethereumjs-testrpc

npm install -g ethereumjs-testrpc

安装 Truffle

npm install -g truffle

测试

truffle
#Truffle v5.1.50 - a development framework for Ethereum

2 搭建第一个 DApp

DApp:Decentralization Application,去中心化应用

原文链接:ETHEREUM PET SHOP – YOUR FIRST DAPP

初始化项目

mkdir pet-shop-tutorial
cd pet-shop-tutorial
truffle unbox pet-shop

注意:这里不能用 truffle init,必须使用 truffle unbox pet-shop

如果这里提示Downloading 失败,则去 googlehosts,复制该文件所有内容,接着替换 /etc/hosts 所有内容(下载 hosts 可以使用 github 加速服务),或者使用下面的:

# GitHub Start
192.30.255.112 gist.github.com
192.30.255.112 github.com
192.30.255.112 www.github.com
151.101.56.133 avatars0.githubusercontent.com
151.101.56.133 avatars1.githubusercontent.com
151.101.56.133 avatars2.githubusercontent.com
151.101.56.133 avatars3.githubusercontent.com
151.101.56.133 avatars4.githubusercontent.com
151.101.56.133 avatars5.githubusercontent.com
151.101.56.133 avatars6.githubusercontent.com
151.101.56.133 avatars7.githubusercontent.com
151.101.56.133 avatars8.githubusercontent.com
151.101.56.133 camo.githubusercontent.com
151.101.56.133 cloud.githubusercontent.com
151.101.56.133 gist.githubusercontent.com
151.101.56.133 marketplace-screenshots.githubusercontent.com
151.101.56.133 raw.githubusercontent.com
151.101.56.133 repository-images.githubusercontent.com
151.101.56.133 user-images.githubusercontent.com
# GitHub End
vi /etc/hosts

接着在 truffle unbox pet-shop 即可成功,此时目录结构应如下:
在这里插入图片描述

编写智能合约

vi contracts/Adoption.sol

输入以下内容:

pragma solidity ^0.5.0;
contract Adoption {
//领养的合约
address[16] public adopters;//存着宠物是否被领养的账户地址
function adopt(uint petId) public returns (uint) {
  require(petId >= 0 && petId <= 15);
  //当petID 满足 [0,15],将调用此函数用户赋值给adopters数组
  adopters[petId] = msg.sender;
  return petId;
}
//一次性获取所有的宠物的领养状态
function getAdopters() public view returns (address[16] memory) {
  return adopters;
}
}

编译智能合约

truffle compile

在这里插入图片描述

迁移

  • 将智能合约迁移到区块链上:迁移用于部署脚本,可以更改应用程序智能合约的状态。
vi migrations/2_deploy_contracts.js

输入以下内容:

//将钢协写的合约名为 Adoption 的智能合约部署
var Adoption = artifacts.require("Adoption");
//这里是把已经编译的智能合约的二进制文件给部署到区块链上
module.exports = function(deployer) {
  deployer.deploy(Adoption);
};

安装 Ganache

  • Ganache:一个用于Ethereum开发的个人区块链,可以使用它来部署智能合约、开发应用程序和运行测试,会在端口7545上生成一个本地运行的区块链

Ganache有2种版本:界面版本和命令行版本

命令行版本

安装

npm install -g ganache-cli

启动

ganache-cli

带界面版本
前往 ganache 下载后缀名为 AppImage的文件,这里版本为2.5.4

在这里插入图片描述
2 种方法下载:

  1. 使用 wget 命令下载(国内速度慢)
wget https://github.com/trufflesuite/ganache/releases/download/v2.5.4/ganache-2.5.4-linux-x86_64.AppImage
  1. 百度网盘(提取码:chao)下载,或者使用浏览器或其他下载工具下载,然后复制到虚拟机里面

下载 ganache-2.5.4-linux-x86_64.AppImage 后,双击即可运行,如果因为屏幕分辨率原因导致显示不全的,解决方案如下:

  1. 使用 Alt + 鼠标移动
  2. 改变分辨率(推荐)
xrandr	#用于显示支持的分辨率
xrandr --size 1280x768

效果如下:
在这里插入图片描述

迁移智能合约到区块链

truffle migrate

在这里插入图片描述
迁移前后的变化:

  • 区块数目由 0 变为 4
  • 迁移需要一定的交易费(total cost)

使用 Solidity 测试智能合约

vi test/TestAdoption.sol

输入以下内容:

pragma solidity ^0.5.0;

//导入的包 Assert 中包括了 equality,inequality 以及 emptiness函数
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";

contract TestAdoption {
 // 获取部署合约实例的地址
 Adoption adoption = Adoption(DeployedAddresses.Adoption());

// 测试一下智能合约中的 adopt 函数
function testUserCanAdoptPet() public {
  uint returnedId = adoption.adopt(expectedPetId);

  Assert.equal(returnedId, expectedPetId, "被收养的宠物与被返回的宠物 id 一致");
}

// 测试一下 单个 adopter 是否能正常返回
function testGetAdopterAddressByPetId() public {
  address adopter = adoption.adopters(expectedPetId);

  Assert.equal(adopter, expectedAdopter, "宠物的主人的在该实例化合同中");
}

// 测试所有的 adopters
function testGetAdopterAddressByPetIdInArray() public {
  // 领养者地址存到内存中
  address[16] memory adopters = adoption.getAdopters();

  Assert.equal(adopters[expectedPetId], expectedAdopter, "Owner of the expected pet should be this contract");
}

运行

truffle test

在这里插入图片描述

实例化 web3

打开 app.js

gedit src/js/app.js

替换为以下内容并保存:

App = {
  web3Provider: null,
  contracts: {},

  init: async function() {
    // 初始化
    $.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 await App.initWeb3();
  },

  initWeb3: async function() {
if (window.ethereum) {
  App.web3Provider = window.ethereum;
  try {
    // 等待以太坊启动
    await window.ethereum.enable();
  } catch (error) {
    console.error("User denied account access")
  }
}
else if (window.web3) {
  App.web3Provider = window.web3.currentProvider;
}
else {
  App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3Provider);
    return App.initContract();
  },

  initContract: function() {
    $.getJSON('Adoption.json', function(data) {
  // 获取实例化的智能合约并部署
  var AdoptionArtifact = data;
  App.contracts.Adoption = TruffleContract(AdoptionArtifact);

  // 为只能合约设置提供者
  App.contracts.Adoption.setProvider(App.web3Provider);

  // 使用智能合约来取回和标记被收养的宠物
  return App.markAdopted();
});

    return App.bindEvents();
  },

  bindEvents: function() {
    $(document).on('click', '.btn-adopt', App.handleAdopt);
  },

  markAdopted: function() {
    var adoptionInstance;

App.contracts.Adoption.deployed().then(function(instance) {
  adoptionInstance = instance;

  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);
});
  },

  handleAdopt: function(event) {
    event.preventDefault();

    var petId = parseInt($(event.target).data('id'));

    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();
  });
});

在浏览器中与 DApp 交互

打开 Firefox,在设置里选择 Add-ons(插件),搜索 MetaMask并安装,一路确定即可

到达该页面后,复制 Ganache 中的MNEMONIC 下的文字
在这里插入图片描述
粘贴到 Wallet Seed 中,密码随便设置
在这里插入图片描述
其他设置同原链接的步骤

启动 DApp

由于这个 DApp 的 web 需要 google 的资源,先得安装科学上网工具(这里已经安装)或者更改 src 下 index.html 的资源引用。
启动 web 服务

npm run dev

这里可能会不弹出浏览器,则手动在 FireFox 浏览器输入地址:

http://localhost:3000

其他同原文章,效果如下
在这里插入图片描述
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐