参考博客
https://blog.csdn.net/weixin_42172261/article/details/106915121
https://infura.io/dashboard/ethereum(创建项目的网站)
https://blog.csdn.net/weixin_40788897/article/details/103918598
https://blog.csdn.net/shangsongwww/article/details/89977236
https://blog.csdn.net/u011240877/article/details/76582670
https://blog.csdn.net/qq_20513027/article/details/85041353
跟着博客学习https://www.qikegu.com/docs/4839
环境安装
ubuntu下安装nodejs和npm
安装nodejs :
sudo apt-get install nodejs
运行 nodejs -v
会弹出安装node的版本号
这里使用的是 nodejs 并不是常用的node ,可以通过
sudo ln -s /usr/bin/nodejs /usr/bin/node
命令让node与nodejs
建立软连接,接着就可以使用 node命令
安装npm:
sudo apt-get install npm
测试安装是否成功: npm -v
弹出安装的版本号,即可证明安装成功
Truffle 框架安装
使用 $ npm install -g truffle 这个一直失败
于是,看了一些帖子,找到了它
sudo -E npm install truffle@2.0.8 -g
truffle --version
出现Truffle v5.0.35 - a development framework for Ethereum成功。
安装Ganache
我使用了图形界面,因为用命令行的我总是报错。
ganache:用于测试和开发的快速以太坊RPC客户端,其目前有两个版本:图形界面的版本和命令行版本,任选一个下载即可。我使用了图形界面,因为命令行的我总是报错。
图形界面版本
1)对于Linux系统,在 https://github.com/trufflesuite/ganache/releases下载以.AppImage为后缀的包(windows:.appx mac:dmg)
或在终端输入wget https://github.com/trufflesuite/ganache/releases/download/v1.1.0/ganache-1.1.0-x86_64.AppImage
进行下载
2)修改权限chmod +x ganache-1.1.0-x86_64.AppImage
3)直接在命令行输入sudo ./ganache-1.1.0-x86_64.AppImage
即可运行
下面是命令行的方式,大家可以参考。
1.命令行版本ganache-cli
1)输入sudo npm install -g ganache-cli
2)将truffle复制到/usr/local/bin路径中,输入:
sudo ln -s /opt/node-v8.9.4-linux-x64/bin/ganache-cli /usr/local/bin/ganache-cli
安装 MetaMask
要安装Chrome版本MetaMask ,前往*Chrome网上应用店*,然后点击添加到Chrome按钮。
要安装FireFox版本MetaMask ,前往*Firefox附加组件页面*并单击添加到Firefox按钮。
Ganache本地区块链
启动Ganache,因为我用的是图像化界面,所以使用sudo ./ganache-1.1.0-x86_64.AppImage
即可运行。
开发智能合约
首先创建项目目录:
$ mkdir mydapp
$ cd mydapp
$ truffle init
truffle init:初始化项目,将生成项目模板文件。
添加package.json文件
package.json是npm用来管理包的配置文件,在项目根目录下创建此文件,内容如下:
{
"name": "ethereum-demo",
"version": "1.0.0",
"description": "以太坊demo",
"main": "truffle-config.js",
"directories": {
"test": "test"
},
"scripts": {
"dev": "lite-server",
"test": "echo \"Error: no test specified\" && sexit 1"
},
"author": "kevinhwu@qikegu.com",
"license": "ISC",
"devDependencies": {
"@truffle/contract": "^4.0.33",
"dotenv": "^8.1.0",
"lite-server": "^2.5.4",
"truffle-hdwallet-provider": "^1.0.17"
}
}
ps:不能少了 “dev”: “lite-server”,不然后面运行服务器的时候容易出问题。
添加智能合约源文件
在contracts 目录中创建一个新文件MyContract.sol,内容如下所示:
// 声明solidity版本
pragma solidity ^0.5.0;
// 声明智能合约MyContract,合约的所有代码都包含在花括号中。
contract MyContract {
// 声明一个名为value的状态变量
string value;
// 合约构造函数,每当将合约部署到网络时都会调用它。
// 此函数具有public函数修饰符,以确保它对公共接口可用。
// 在这个函数中,我们将公共变量value的值设置为“myValue”。
constructor() public {
value = "myValue";
}
// 本函数读取值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
// 它还包含view修饰符并指定一个字符串返回值。
function get() public view returns(string memory ) {
return value;
}
// 本函数设置值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
function set(string memory _value) public {
value = _value;
}
}
PS:pragma solidity ^0.5.0;,构造函数constructor() public, view修饰符这些在编译的时候都会报错,我用了最简单粗暴的方法,把他们删掉了。出错原因目前不明。
编译项目
$ truffle compile
部署智能合约到Ganache
更新配置文件
更新项目的配置文件,修改网络配置连接到本地区块链网络(Ganache)。
打开位于项目根目录下的truffle-config.js文件,修改内容如下:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
}
},
solc: {
optimizer: {
enabled: true,
runs: 200
}
}
}
这些网络配置,包括ip地址、端口等,应该与Ganache的网络配置匹配:
创建迁移脚本
接下来,我们将在migrations目录中创建迁移脚本,告诉Truffle如何部署智能合约,在该目录中创建文件2_deploy_contracts.js。
vi 2_deploy_contracts.js
注意,在migrations目录中所有文件都有编号,作用是让Truffle知道执行它们的顺序。
2_deploy_contracts.js文件内容如下:
var MyContract = artifacts.require("./MyContract.sol");
module.exports = function(deployer) {
deployer.deploy(MyContract);
};
执行迁移命令
$ truffle migrate
使用 truffle console 访问智能合约
启动 truffle console:
$ truffle console
MyContract.deployed().then((instance) => { app = instance } )
app.get()
// => 'myValue'
app.get()
// => 'myValue'
app.get()
// => 'New Value'
.exit
由于第一句MyContract.deployed().then((instance) => { app = instance } )
出现问题,后面几句都没运行成功。我运行了`MyContract.deployed(),可以成功。
智能合约测试(truffle test)
在项目根目录下的test目录中,添加测试脚本文件: MyContract.js
vi MyContract.js
MyContract.js中的测试代码:
// 首先,`require`合约并将其分配给一个变量`MyContract`
const MyContract = artifacts.require('./MyContract.sol');
// 调用“contract”函数,并在回调函数中编写所有测试
// 回调函数提供一个“accounts”变量,表示本地区块链上的所有帐户。
contract('MyContract', (accounts) => {
// 第1个测试:调用get()函数,检查返回值,测试合约中value初始值是否是: 'myValue'
it('initializes with the correct value', async () => {
// 获取合约实例
const myContract = await MyContract.deployed()
const value = await myContract.get()
// 使用断言测试value的值
assert.equal(value, 'myValue')
})
// 第2个测试: 调用set()函数来设置value值,然后调用get()函数来确保更新了值
it('can update the value', async () => {
const myContract = await MyContract.deployed()
myContract.set('New Value');
const value = await myContract.get()
assert.equal(value, 'New Value')
})
})
运行测试脚本
$ truffle test
连接公链
设置钱包来管理公链帐户
打开Ganache,主界面上可以看到一个名为“MNEMONIC”的部分:这是一个种子短语(几个单词的集合),用于构建由Ganache管理的钱包。我们可以使用这个种子短语加密重建钱包,来连接到公链。
复制这个值,保存到一个秘密文件,MNEMONIC是一个秘密值,需要保密。在项目根目录中创建一个.env文件,保存MNEMONIC值,如下所示:
$ vi .env
MNEMONIC="你的mnemonic"
连接到以太坊节点
比较方便的方法是,使用Infura访问Ethereum节点。Infura(https://infura.io/dashboard/ethereum)
是一个免费提供Ethereum节点的服务。
在Infura上注册账号,创建项目,在项目详情页上可以查看API KEY
使用API KEY,就可以访问以太坊网络节点。
在.env文件中添加Infura api key的配置:
INFURA_API_KEY="https://kovan.infura.io/v3/543526cd4d3846acbc3826484e934564"
MNEMONIC="你的mnemonic"
更新项目设置
修改truffle-config.js文件
// 导入dotenv库创用于读取`.env`文件中的设置
require('dotenv').config();
// 导入truffle-hdwallet-provider库重建钱包
const HDWalletProvider = require('truffle-hdwallet-provider');
module.exports = {
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
kovan: {
provider: () => new HDWalletProvider(
process.env.MNEMONIC,
process.env.INFURA_API_KEY
),
gas: 5000000,
gasPrice: 25000000000,
network_id: 42
},
},
solc: {
optimizer: {
enabled: true,
runs: 200
}
}
}
访问以太坊节点
由于用到了dotenv与truffle-hdwallet-provider这2个库,我们需要先安装:
切换到项目目录,执行以下命令
npm install dotenv --save-dev
npm install truffle-hdwallet-provider --save-dev
访问以太坊节点
使用truffle console连接到公共区块链网络:
$ truffle console --network kovan
复制要验证连接,可以从区块链中读取一些数据,获取一些关于最新区块的信息,在控制台上执行:
web3.eth.getBlock('latest').then(console.log)
上面这句话我又没成功,于是我就执行了web3.eth.getBlock('latest')
部署智能合约到公链
部署需要消耗Gas,获取测试以太币用于部署
可以从Kovan faucet Gitter聊天室(https://gitter.im/kovan-testnet/faucet#)获取测试用的伪以太币。只需把钱包地址发送出去,约5分钟内,有人会给你发测试用的伪以太币。
打开Ganache并复制列表中第一个帐户的地址(钱包地址),类似下面所示:
0x29920e756f41F8e691aE0b12D417C19204371E91
复制
发送到聊天室内,稍等片刻,你的账号将收到一笔以太币。
部署智能合约
现在帐户里已经有了资金,可以进行部署了。
执行部署命令:
truffle migrate --network kovan
一旦部署完成,应该会看到部署成功的消息。
验证部署
现在打开truffle控制台,与kovan测试网络上的智能合约进行交互:
$ truffle console --network kovan
复制
在控制台中执行:
truffle(kovan)> MyContract.deployed().then((c) => { contract = c })
我又只能执行半句话MyContract.deployed()
.
然后:(下面的我也无法执行)
truffle(kovan)> contract.get()
'myValue'
truffle(kovan)> contract.set("hello world")
{ tx:
'0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37',
receipt:
{ blockHash:
'0xe03d0f43d85f4e41c18a90aa563ebda08899c6b9c38d0cd7779937046e2aed0c',
blockNumber: 13447763,
contractAddress: null,
cumulativeGasUsed: 33629,
from: '0x29920e756f41f8e691ae0b12d417c19204371e91',
gasUsed: 33629,
logs: [],
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
root: null,
status: true,
to: '0x4d3cfaf8457cea76c0409f989f9870115b4d2d82',
transactionHash:
'0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37',
transactionIndex: 0,
rawLogs: [] },
logs: [] }
truffle(kovan)> contract.get()
'hello world'
truffle脚本
在项目根目录下,创建script.js
文件,内容如下:
module.exports = function(callback) {
web3.eth.getBlock('latest').then(console.log)
}
该脚本将从Kovan测试网络获取最新区块的信息。
执行脚本:
truffle exec script.js --network kovan
下面的代码智能合约MyContract中,读取value值,将script.js
脚本文件中的代码替换为:
const MyContract = artifacts.require("./MyContract.sol");
module.exports = async function(callback) {
const contract = await MyContract.deployed()
const value = await contract.get()
console.log("Value:", value)
}
执行脚本:
truffle exec script.js --network kovan
输出:
Value: hello world
脚本运行器是一个非常有用的功能
让浏览器支持区块链(MetaMask)
安装MetaMask
我们将为Chrome浏览器安装Metamask钱包插件(需翻墙)。
安装好后,确保插件的启用按钮打开,在浏览器的右上角会看到一个狐狸🦊图标。
导入账号
把钱包账号从Ganache导入到Metamask中,这样我们就可以连接到区块链了。
打开Ganache主界面,复制MNEMONIC(随机种子),也可以叫私钥。打开Metamask,选择通过Seed Phrase导入账号,把复制MNEMONIC的值,粘贴到Wallet Seed。
可以参考这篇:https://blog.csdn.net/shangsongwww/article/details/89977236
进入钱包
查看Kovan网络,可以看到里面有一些测试以太币余额。
智能合约前端页面
显示当前连接的帐户
配置web服务器
首先,让我们来配置web服务器。服务器使用lite-server,安装lite-server:
$ npm install lite-server --save-dev
项目根目录下,创建lite-server的配置文件bs-config.json,内容如下:
{
"server": {
"baseDir": [
"./src",
"./build/contracts"
],
"routes": {
"/vendor": "./node_modules"
}
}
}
创建前端页面
项目根目录下,创建src目录,用于存放前端页面。
前端页面包含2个文件:
src/index.html
src/app.js
index.html
添加index.html页面,内容如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>以太坊 DApp Demo</title>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>账号: <span id="account"></span></h1>
<hr>
<div id="content">
<h2>智能合约:MyContract</b></h2>
<p>获取智能合约中的value值: <span id="value"></span></p>
<h5>设置value值</h5>
<form onSubmit="App.set(); return false;" role="form">
<div >
<input id="newValue" type="text"></input>
</div>
<button type="submit" >设置</button>
</form>
</div>
<div id="loader">正在加载...</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://etherscan.io/jss/web3.min.js"></script>
<script src="vendor/@truffle/contract/dist/truffle-contract.js"></script>
<script src="app.js"></script>
</body>
</html>
添加javascript脚本文件:app.js
App = {
web3Provider: null,
contracts: {},
account: '0x0',
loading: false,
contractInstance: null,
init: async () => {
// 加载web3
await App.loadWeb3()
// 加载智能合约
await App.loadContract()
// 网页刷新
await App.render()
},
// https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8
loadWeb3: async () => {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider
web3 = new Web3(web3.currentProvider)
} else {
window.alert("Please connect to Metamask.")
}
// MetaMask新版本…
if (window.ethereum) {
window.web3 = new Web3(ethereum)
try {
// 向用户请求帐户访问
await ethereum.enable()
// 用户允许使用账户
web3.eth.sendTransaction({/* ... */ })
} catch (error) {
// 用户拒绝使用账户
}
}
// MetaMask老版本…
else if (window.web3) {
App.web3Provider = web3.currentProvider
window.web3 = new Web3(web3.currentProvider)
// 无需向用户请求,可以直接使用账号
web3.eth.sendTransaction({/* ... */ })
}
// 没有安装以太坊钱包插件(MetaMask)...
else {
console.log('需要安装以太坊钱包插件(例如MetaMask)才能使用!')
}
},
loadContract: async () => {
const contract = await $.getJSON('MyContract.json')
App.contracts.MyContract = TruffleContract(contract)
App.contracts.MyContract.setProvider(App.web3Provider)
},
render: async () => {
// 如果正在加载,直接返回,避免重复操作
if (App.loading) {
return
}
// 更新app加载状态
App.setLoading(true)
// 设置当前区块链帐户
const accounts = await ethereum.enable()
App.account = accounts[0]
$('#account').html(App.account)
// 加载智能合约
const contract = await App.contracts.MyContract.deployed()
App.contractInstance = contract
const value = await App.contractInstance.get()
$('#value').html(value)
App.setLoading(false)
},
set: async () => {
App.setLoading(true)
const newValue = $('#newValue').val()
await App.contractInstance.set(newValue, {from: App.account})
window.alert('更新成功,页面值不会马上更新,等待几秒后多刷新几次。')
App.setLoading(false)
},
setLoading: (boolean) => {
App.loading = boolean
const loader = $('#loader')
const content = $('#content')
if (boolean) {
loader.show()
content.hide()
} else {
loader.hide()
content.show()
}
}
}
$(document).ready(function () {
App.init()
});
现在安装、启动服务器:
$ npm install @truffle/contract --save-dev
$ npm run dev
然后使用安装了MetaMask插件的Chrome浏览器,打开网址:http://localhost:3000,就可以查看前端页面,与区块链上的智能合约进行交互。
问题汇总
1、contracts/Migrations.sol: ParsedContract.sol:7:14: ParserError: Expected identifier, got 'LParen'
constructor() public {
^
Compilation failed. See above.
~/eth-hunt/
truffle 编译构造函数出问题。目前还没有解决。
2、ubuntu中如何创建一个.env文件
$ vi .env
在ubuntu中,创建任何后缀文件,都用vi
3、MyContract.deployed().then((instance) => { app = instance } )
这个语句执行不了,,每次只能执行前半句MyContract.deployed().
4、TypeError: web3.eth.contract is not a function
参考:https://blog.csdn.net/chyabc123456hh/article/details/107858454
5、lzk@lzk-virtual-machine:~/mydapp/src$ npm run dev
npm ERR! missing script: dev
原因是package.json文件中少了配置。dev.
6、truffle create contract MyContract报错
改为truffle create:contract MyContract
7、truffle compile
TypeError: this is not a typed array.
升级npm
npm update npm -g
很多问题,都不同版本引起的问题。
慢慢摸索中,有一起学习区块链方向的小伙伴,可以加我一起探讨!