
一、安装DApp开发环境
1.1 安装Node.js
https://nodejs.org/en/download/
我们使用官方长期支持的 Latest LTS Version: 12.18.4 (includes npm 6.14.6)版本,点击这个链接下载32位安装包,32位安装包即可用于32位系统,也可用于64位系统。如果你确认你的系统是64位,也可以下载64位包装包。下载后直接安装即可。安装完毕,打开一个控制台窗口,可以使用node了:
C:\Users\Administrator>node -v
v12.18.4
1.2 安装Geth
https://geth.ethereum.org/downloads/
https://gethstore.blob.core.windows.net/builds/geth-windows-amd64-1.9.21-0287d548.exe
下载64位或32位Geth安装程序,然后进行安装。安装完毕后打开一个控制台,执行命令验证安装成功:
C:\Users\Administrator>geth version
Geth
Version: 1.9.21-stable
Git Commit: 0287d54847d3297f3ced62cd83a4c95ccbe0045b
Git Commit Date: 20200909
Architecture: amd64
Protocol Versions: [65 64 63]
Go Version: go1.15
Operating System: windows
GOPATH=
GOROOT=go
C:\Users\Administrator>
1.3 安装solidity编译器
C:\Users\Administrator>npm install -g solc
安装完毕后,执行命令验证安装成功
C:\Users\Administrator>solcjs --version
0.7.1+commit.f4a555be.Emscripten.clang
1.4安装web3
web3.js是一组用来和本地或远程以太坊节点进行交互的js库,它可以使用HTTP或IPC建立与以太坊节点旳连接。
Web3的安装过程使用了git,因此需要先安装windows版的git命令行。下载64位或32位的git安装程序,本地安装后在继续安装web3。
C:\Users\Administrator>npm install -g web3
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this
npm WARN deprecated multicodec@0.5.7: stable api reached
> keccak@3.0.1 install C:\Users\Administrator\AppData\Roaming\npm\node_modules\web3\node_modules\keccak
> node-gyp-build || exit 0
> bufferutil@4.0.1 install C:\Users\Administrator\AppData\Roaming\npm\node_modules\web3\node_modules\bufferutil
> node-gyp-build
> secp256k1@4.0.2 install C:\Users\Administrator\AppData\Roaming\npm\node_modules\web3\node_modules\secp256k1
> node-gyp-build || exit 0
> utf-8-validate@5.0.2 install C:\Users\Administrator\AppData\Roaming\npm\node_modules\web3\node_modules\utf-8-validate
> node-gyp-build
> web3@1.3.0 postinstall C:\Users\Administrator\AppData\Roaming\npm\node_modules\web3
> node angular-patch.js
+ web3@1.3.0
added 322 packages from 318 contributors in 85.036s
安装验证:
C:\Users\guow> node –p 'require("web3")'
{[Function: Web3]
providers:{…}}
1.5安装truffle框架
Truffle是什么?
Truffle是针对基于以太坊的Solidity语言的一套开发框架。本身基于Javascript。
执行以下命令安装truffle开发框架:
C:\Users\Administrator>npm install -g truffle

验证安装:
C:\Users\Administrator>truffle.cmd version
Truffle v5.1.45 (core: 5.1.45)
Solidity v0.5.16 (solc-js)
Node v12.18.4
Web3.js v1.2.1
1.6安装webpack
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
执行以下命令安装webpack:
C:\Users\Administrator>npm install -g webpack

验证安装
C:\Users\Administrator>webpack -v
4.44.2
三、运行私链节点
2.1创世块配置
创建一个节点目录node1,并在其中创建私链的创世块配置文件:
C:\Users\guow> mkdir node1
C:\Users\guow> cd node1
C:\Users\guow\node1> notepad private.json
然后编辑内容如下:
{
"config": {
"chainId": 7878
},
"difficulty" : "0x2000",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc": {
"0x5fc5cEce9458b3977Df2217507b45745Ce7Ec5B0": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
}
}
}
config.chainId用来声明以太坊网络编号,选择一个大于10的数字即可。
difficulty用来声明挖矿难度,越小的值难度越低,也就能更快速地出块。
2.2初始化私链节点
执行geth的init命令初始化私链节点:
C:\Users\Administrator\node1>geth --datadir .\data init private.json
C:\Users\Administrator\node1>geth --datadir .\data init private.json
INFO [09-24|22:37:48.025] Maximum peer count ETH=50 LES=0 total=50
INFO [09-24|22:37:48.287] Set global gas cap cap=25000000
INFO [09-24|22:37:48.292] Allocated cache and file handles database=C:\Users\Administrator\node1\data\geth\chaindata cache=16.00MiB handles=16
INFO [09-24|22:37:48.498] Writing custom genesis block
INFO [09-24|22:37:48.509] Persisted trie from memory database nodes=1 size=171.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [09-24|22:37:48.542] Successfully wrote genesis state database=chaindata hash="64cc5d…a0d013"
INFO [09-24|22:37:48.553] Allocated cache and file handles database=C:\Users\Administrator\node1\data\geth\lightchaindata cache=16.00MiB handles=16
INFO [09-24|22:37:48.706] Writing custom genesis block
INFO [09-24|22:37:48.709] Persisted trie from memory database nodes=1 size=171.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [09-24|22:37:48.724] Successfully wrote genesis state database=lightchaindata hash="64cc5d…a0d013"
这会在当前目录下创建data目录,用来保存区块数据及账户信息:
C:\Users\Administrator\node1>dir
驱动器 C 中的卷没有标签。
卷的序列号是 2C83-78AB
C:\Users\Administrator\node1 的目录
2020/09/24 22:32 <DIR> .
2020/09/24 22:32 <DIR> ..
2020/09/24 22:37 <DIR> data
2020/09/24 22:36 521 private.json
1 个文件 521 字节
3 个目录 10,227,728,384 可用字节
C:\Users\Administrator\node1>
可以上述命令写到一个脚本init.cmd里,这样避免每次都输入那么多记不住的东西。文件内容如下:
geth --datadir .\data init private.json
在部署下一个节点时,就可以直接执行这个脚本进行初始化了。例如,在另一台机器上:
C:\Users\guow\node1> init.cmd
2.3启动私链节点
从指定的私链数据目录启动并设定一个不同的网络编号来启动节点:
C:\Users\Administrator\node1>geth --rpc --datadir .\data --networkid 7878 console

#增加--nodiscover 关闭p2p网络的自动发现,解决问题:INFO [09-24|17:44:47.158] Looking for peers peercount=0 tried=81 static=0
#待验证,win 加上--rpc参数后增加--nodiscover 参数无效
C:\Users\Administrator\node1>geth --rpc --datadir .\data --nodiscover --networkid 7878 console

同样,你可以用一个脚本console.cmd来简化启动节点时的输入,文件内容如下:
geth --rpc \
--rpcaddr 0.0.0.0 \
--rpccorsdomain "*" \
--datadir ./data \
--networkid 7878 \
console
rpcaddr参数用来声明节点RPC API的监听地址,设为0.0.0.0就可以从其他机器访问API了;
rpccorsdomain参数是为了解决web3从浏览器中跨域调用的安全限制问题。以后启动节点,只要直接执行这个脚本即可:
C:\Users\guow\node1> console.cmd
2.4 账户管理
2.4.1 查看账户列表
在geth控制台,使用eth对象的accounts属性查看目前的账户列表:
> eth.accounts
[]
因为我们还没有创建账户,所以这个列表还是空的。
2.4.2创建新账户
在geth控制台,使用personal对象的newAccount()方法创建一个新账户,参数为你自己选择的密码:
> personal.newAccount('78787878')
INFO [09-24|22:48:28.324] Your new key was generated address=0xF9E7eCf50f36117a905B27489199220F30900515
WARN [09-24|22:48:28.329] Please backup your key file! path=C:\Users\Administrator\node1\data\keystore\UTC--2020-09-24T14-48-25.811601100Z--f9e7ecf50f36117a905b27489199220f30900515
WARN [09-24|22:48:28.338] Please remember your password!
"0xf9e7ecf50f36117a905b27489199220f30900515"
输出就是新创建的账户地址(公钥),你的输出不会和上面的示例相同。geth会保存到数据目录下的keystore文件中。密码要自己记住,以后还需要用到。
2.4.3查询账户余额
在geth控制台,使用personal对象的getBalance()方法获取指定账户的余额,参数为账户地址:
> eth.getBalance(eth.accounts[0])
0
>
或者直接输入账户地址:
> eth.getBalance('0xf9e7ecf50f36117a905b27489199220f30900515')
0
新创建的账户,余额果然为0。
2.4.4挖矿
没钱的账户什么也干不了,需要挖矿来挣点钱。在geth控制台执行miner对象的start()方法来启动挖矿:
> miner.start(1)
等几分钟以后,检查账户余额:
> eth.getBalance(eth.accounts[0])
15000000000000000000
钱不少了,15ETH了。执行miner对象的stop()方法停止挖矿:
> miner.stop()
2.4.5解锁账户
在部署合约时需要一个解锁的账户。在geth控制台使用personal对象的unlockAccount()方法来解锁指定的账户,参数为账户地址和账户密码(在创建账户时指定的那个密码):
> eth.unlockAccount(eth.accounts[0],'78787878')
> personal.unlockAccount(eth.accounts[0],'78787878')
true
三、构建示例项目
3.1 新建DApp项目
执行以下命令创建项目目录并进入该目录:
C:\Users\guow> mkdir demo
C:\Users\guow> cd demo
然后用webpack模版初始化项目骨架结构:
C:\Users\Administrator\demo>truffle.cmd unbox webpack
Starting unbox...
=================
√ Preparing to download box
× Downloading
Unbox failed!
× Downloading
Unbox failed!
RequestError: Error: connect ETIMEDOUT 151.101.108.133:443
at new RequestError (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\request-promise-core\lib\errors.js:14:1)
at Request.plumbing.callback (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\request-promise-core\lib\plumbing.js:87:1)
at Request.RP$callback [as _callback] (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\request-promise-core\lib\plumbing.js:46:1)
at self.callback (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\request\request.js:185:1)
at Request.emit (events.js:315:20)
at Request.onRequestError (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\request\request.js:881:1)
at ClientRequest.emit (events.js:315:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:315:20)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
Truffle v5.1.45 (core: 5.1.45)
Node v12.18.4

解决方案:hosts方案,将以下连接的hosts文件追加至本机hosts文件之后,报错,再次执行成功,喵啊~
https://github.com/googlehosts/hosts/blob/master/hosts-files/hosts

C:\Users\guow\demo> truffle.cmd unbox webpack
Downloading…
Unpacking…
Setting up…
Unbox successful. Sweet!
3.2 安装项目依赖的NPM包
执行以下命令安装nmp包:
C:\Users\guow\demo$ npm install
#报错
C:\Users\Administrator\demo>npm install
npm WARN saveError ENOENT: no such file or directory, open 'C:\Users\Administrator\package.json'
npm WARN enoent ENOENT: no such file or directory, open 'C:\Users\Administrator\package.json'
npm WARN Administrator No description
npm WARN Administrator No repository field.
npm WARN Administrator No README data
npm WARN Administrator No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\watchpack-chokidar2\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
up to date in 5.784s
#解决方案
C:\Users\Administrator>npm init -y
3.3 修改truffle配置
如果你使用图形版的ganache,不需要修改truffle.js配置文件。否则,需要在truffle.js中,修改port为8545,因为ganache-cli在8545端口监听:
module.exports = {
networks:{
development: {
port: 8545
}
}
}
3.4 启动节点
执行以下命令启动节点仿真器,以便部署合约并执行交易:
C:\Users\guow\node1> console.cmd
注意:为了在节点上部署合约,别忘了启动geth后先解锁账户:
> personal.unlockAcount(eth.accounts[0],'78787878')
true
3.5 编译合约
执行以下命令编译项目合约:
C:\Users\guow\demo> truffle.cmd compile
3.6 部署合约
执行以下命令来部署合约:
C:\Users\guow\demo> truffle.cmd migrate
#错误
C:\Users\Administrator\demo1>truffle.cmd migrate
Compiling your contracts...
===========================
> Compiling .\contracts\ConvertLib.sol
> Artifacts written to C:\Users\Administrator\demo1\build\contracts
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
> Something went wrong while attempting to connect to the network. Check your network configuration.
ProviderError:
Could not connect to your Ethereum client with the following parameters:
- host > 127.0.0.1
- port > 7545
- network_id > 5777
Please check that your Ethereum client:
- is running
- is accepting RPC connections (i.e., "--rpc" option is used in geth)
- is accessible over the network
- is properly configured in your Truffle configuration file (truffle-config.js)
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\provider\wrapper.js:75:1
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\provider\wrapper.js:107:1
at XMLHttpRequest.request.onreadystatechange (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\web3-providers-http\src\index.js:96:1)
at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request-event-target.js:34:1)
at XMLHttpRequest._setReadyState (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:208:1)
at XMLHttpRequest._onHttpRequestError (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:349:1)
at ClientRequest.<anonymous> (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:252:47)
at ClientRequest.emit (events.js:315:20)
at Socket.socketErrorListener (_http_client.js:426:9)
at Socket.emit (events.js:315:20)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
Truffle v5.1.45 (core: 5.1.45)
Node v12.18.4
#解决方案,修改C:\Users\Administrator\demo1\truffle-config.js
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
如果你之前忘了在geth控制台解锁账户,会看到如下错误,参考前面说明进行解锁即可:
Error: authentication needed: password or unlock
C:\Users\Administrator\demo1>truffle.cmd migrate
Compiling your contracts...
===========================
> Compiling .\contracts\ConvertLib.sol
> Artifacts written to C:\Users\Administrator\demo1\build\contracts
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Starting migrations...
======================
> Network name: 'development'
> Network id: 7878
> Block gas limit: 4282396671 (0xff402fff)
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
Error: *** Deployment Failed ***
"Migrations" -- Returned error: authentication needed: password or unlock.
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\deployer\src\deployment.js:364:1
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at Migration._deploy (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:68:1)
at Migration._load (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:55:1)
at Migration.run (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:171:1)
at Object.runMigrations (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:150:1)
at Object.runFrom (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:110:1)
at Object.run (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:87:1)
at runMigrations (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:269:1)
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:231:1
Truffle v5.1.45 (core: 5.1.45)
Node v12.18.4
C:\Users\Administrator\demo1>
geth --unlock 0xf9e7ecf50f36117a905b27489199220f30900515 --password 78787878
or
personal.unlockAccount('0xf9e7ecf50f36117a905b27489199220f30900515', '78787878')

错误原因:异常原因:新版本geth,出于安全考虑,默认禁止了HTTP通道解锁账户
解决方式:启动节点命令添加
--allow-insecure-unlock
geth --rpc --datadir .\data --allow-insecure-unlock --networkid 7878 console
> personal.unlockAccount('0xf9e7ecf50f36117a905b27489199220f30900515', '78787878')
true
#再次部署,仍然报错
C:\Users\Administrator\demo1>truffle.cmd migrate
Compiling your contracts...
===========================
> Compiling .\contracts\ConvertLib.sol
> Artifacts written to C:\Users\Administrator\demo1\build\contracts
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Starting migrations...
======================
> Network name: 'development'
> Network id: 7878
> Block gas limit: 4282396671 (0xff402fff)
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
Error: *** Deployment Failed ***
"Migrations" -- Returned error: invalid transaction v, r, s values.
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\deployer\src\deployment.js:364:1
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at Migration._deploy (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:68:1)
at Migration._load (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:55:1)
at Migration.run (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:171:1)
at Object.runMigrations (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:150:1)
at Object.runFrom (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:110:1)
at Object.run (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:87:1)
at runMigrations (C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:269:1)
at C:\Users\Administrator\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:231:1
Truffle v5.1.45 (core: 5.1.45)
Node v12.18.4
C:\Users\Administrator\demo1>
如果已经正确地解锁了账户,你会看到部署过程停止在如下状态:
Replacing Migrations…
… 0x3088762a5bc9…
这是因为truffle在等待部署交易提交,但是我们在私链中还没有启动挖矿。现在切换回geth终端窗口,查看交易池的状态:
> txpool.status
{
pending:1,
queued:0
}
果然有一个挂起的交易!启动挖矿就是了:
> miner.start(1)
稍等小会儿,再查看交易池的状态:
> txpool.status
{
pending:0,
queued:0
}
交易已经成功提交了。我们可以停止挖矿了,因为它太占CPU了:
> miner.stop()
现在切换回truffle那个终端,部署过程也正确地执行完了。
3.7 启动DApp
执行以下命令来启动DApp:
C:\Users\guow\demo> npm run dev
在浏览器里访问http://localhost:8080即可
如果你希望从别的机器也可以访问你的DApp应用,修改一下package.json:
{
scripts:{
"dev": "webpack-dev-server –-host 0.0.0.0"
}
}







