在CENTOS7上玩转Ethereum区块链(6):实验二--对外发布智能合约服务

上次实验中我们通过在项目文件中定位并修改eth 端口访问方式,实现了将eth服务与truffle合约服务分离的目的。通过上次实验,我们可以在tru-host本机实现webpack的转账服务。但截至目前,我们发现浏览器中只能通过http://localhost:8080实现合约服务的访问,不仅其他主机无法通过IP地址来访问tru-host:8080,甚至在tru-host主机本身直接使用192.168.3.103:8080访问合约服务都会招到拒绝(返回“ERR_CONNECTION_REFUSED”)。

今天我们这个实验的目的就是解决上述问题,实现tru-host主机可以对外服务。

假设大家和我一样对nodejs的工作机制不太熟悉(如果熟悉的话,其实直接可以看跳过以下比较绕的一段内容,直接看最后一步...),延续之前的研究思路,由表及里的来分析问题。


0. 提前规划

本实验希望达成以下目的:

(1) 希望局域网内的所有人可以通过tru-host虚机的IP地址(192.168.3.103)访问合约服务(MetaCoin转账服务);

(2) 希望合约服务的端口由原来的8080变更为8088。

(3) 给局域网内任何一台处于eth测试网络(eth-host:8545)的账户(并非在testrpc自动生成的账号)上转2000个MetaCoin!


1. 了解truffle项目的启动方式

truffle项目在完成migrate之后,需执行npm run dev实现本地8080端口的监听。

在此,我们需要对nodejs项目结构和npm执行机制要做一个简单的了解。npm是随同NodeJS一起安装的包管理工具,方便用户在nodejs下实现包的安装、执行和卸载。npm在之前如何安装ethereumjs-testrpc和truffle时,大家应该有所接触了,但今天重点涉及的是npm的脚本执行的配置机制。

在nodejs项目框架中,往往存在这么几个目录和配置文件:

(1) app:存放javascript(js脚本)、stylesheets(css脚本)以及index.html,熟悉网站结构的朋友应该对上述结构很清楚了。

(2) node_modules:存放项目中依赖的包。

(3) package.json:项目包文件定义、依赖关系的定义以及npm可供加载的执行脚本指令的定义,可以让我们非常方便的使用NPM进行项目的发布安装。

刚才提及的npm run dev,实际执行的就是package.json文件中定义在scripts中的"dev"的指令。



也就是说,当我们执行npm run dev时,就相当于等同执行了 webpack-dev-server这么一行指令....但这个”webpack-dev-server“貌似和可执行的脚本貌似不太搭界啊。


2. 深入了解npm run

为此我们有必要进一步了解下npm run的工作机制。npm 允许在package.json文件里面,使用scripts字段定义脚本命令。scripts字段定义的脚本命令,可以是清晰指定的具体的脚本加行参,也可以是默认指定目录下的脚本link。npm run dev时,会npm自动访问package.json并在scripts中解析获取dev具体的脚本命令"webpack-dev-server",并在临时创建的path=./node_modules/.bin/目录下找到"webpack-dev-server" link指向的脚本并加载执行。



我们顺藤摸瓜,可以找到./node_modules/.bin目录下,可以尝试直接执行下该指令:

cd ./node_modules/.bin
./webpack-dev-server

完成到这一步,我们算是找到了在执行 npm run dev真正的执行脚本了。按这个思路,大家还可以摸索下package.json中scripts中的其他命令。

更多有关npm scripts的说明,详见:http://www.ruanyifeng.com/blog/2016/10/npm_scripts.html


3. 了解webpack启动参数

./webpack-dev-server --help
在linux下要习惯使用 --help查询指令的使用方法...看看是否是否有办法实现域名和服务端口的配置:

webpack-dev-server 2.9.1
webpack 2.7.0
Usage: https://webpack.js.org/configuration/dev-server/

Config options:
  --config  Path to the config file
                         [string] [default: webpack.config.js or webpackfile.js]
  --env     Environment passed to the config, when it is a function

Basic options:
  --context    The root directory for resolving entry point and stats
                                       [string] [default: The current directory]
  --entry      The entry point                                          [string]
  --watch, -w  Watch the filesystem for changes                        [boolean]
  --debug      Switch loaders to debug mode                            [boolean]
  --devtool    Enable devtool for better debugging experience (Example:
               --devtool eval-cheap-module-source-map)                  [string]
  -d           shortcut for --debug --devtool eval-cheap-module-source-map
               --output-pathinfo                                       [boolean]
  -p           shortcut for --optimize-minimize --define
               process.env.NODE_ENV="production"                       [boolean]
  --progress   Print compilation progress in percentage                [boolean]

Module options:
  --module-bind       Bind an extension to a loader                     [string]
  --module-bind-post                                                    [string]
  --module-bind-pre                                                     [string]

Output options:
  --output-path                 The output path for compilation assets
                                       [string] [default: The current directory]
  --output-filename             The output filename of the bundle
                                                   [string] [default: [name].js]
  --output-chunk-filename       The output filename for additional chunks
       [string] [default: filename with [id] instead of [name] or [id] prefixed]
  --output-source-map-filename  The output filename for the SourceMap   [string]
  --output-public-path          The public path for the assets          [string]
  --output-jsonp-function       The name of the jsonp function used for chunk
                                loading                                 [string]
  --output-pathinfo             Include a comment with the request for every
                                dependency (require, import, etc.)     [boolean]
  --output-library              Expose the exports of the entry point as library
                                                                        [string]
  --output-library-target       The type for exposing the exports of the entry
                                point as library                        [string]

Advanced options:
  --records-input-path       Path to the records file (reading)         [string]
  --records-output-path      Path to the records file (writing)         [string]
  --records-path             Path to the records file                   [string]
  --define                   Define any free var in the bundle          [string]
  --target                   The targeted execution environment         [string]
  --cache                    Enable in memory caching
                      [boolean] [default: It's enabled by default when watching]
  --watch-stdin, --stdin     close when stdin ends                     [boolean]
  --watch-aggregate-timeout  Timeout for gathering changes while watching
  --watch-poll               The polling interval for watching (also enable
                             polling)                                  [boolean]
  --hot                      Enables Hot Module Replacement            [boolean]
  --prefetch                 Prefetch this request (Example: --prefetch
                             ./file.js)                                 [string]
  --provide                  Provide these modules as free vars in all modules
                             (Example: --provide jQuery=jquery)         [string]
  --labeled-modules          Enables labeled modules                   [boolean]
  --plugin                   Load this plugin                           [string]
  --bail                     Abort the compilation on first error      [boolean]
  --profile                  Profile the compilation and include information in
                             stats                                     [boolean]
  --hot-only                 Do not refresh page if HMR fails          [boolean]

Resolving options:
  --resolve-alias         Setup a module alias for resolving (Example:
                          jquery-plugin=jquery.plugin)                  [string]
  --resolve-extensions    Setup extensions that should be used to resolve
                          modules (Example: --resolve-extensions .es6 .js)
                                                                         [array]
  --resolve-loader-alias  Setup a loader alias for resolving            [string]

Optimizing options:
  --optimize-max-chunks      Try to keep the chunk count below a limit
  --optimize-min-chunk-size  Try to keep the chunk size above a limit
  --optimize-minimize        Minimize javascript and switches loaders to
                             minimizing                                [boolean]

Stats options:
  --color, --colors   Enables/Disables colors on the console
                                           [boolean] [default: (supports-color)]
  --info              Info                             [boolean] [default: true]
  --quiet             Quiet                                            [boolean]
  --client-log-level  Log level in the browser (info, warning, error or none)
                                                      [string] [default: "info"]

SSL options:
  --https           HTTPS                                              [boolean]
  --key             Path to a SSL key.                                  [string]
  --cert            Path to a SSL certificate.                          [string]
  --cacert          Path to a SSL CA certificate.                       [string]
  --pfx             Path to a SSL pfx file.                             [string]
  --pfx-passphrase  Passphrase for pfx file.                            [string]

Response options:
  --content-base          A directory or URL to serve HTML content from.[string]
  --watch-content-base    Enable live-reloading of the content-base.   [boolean]
  --history-api-fallback  Fallback to /index.html for Single Page Applications.
                                                                       [boolean]
  --compress              Enable gzip compression                      [boolean]

Connection options:
  --port                The port
  --disable-host-check  Will not check the host                        [boolean]
  --socket              Socket to listen
  --public              The public hostname/ip address of the server    [string]
  --host                The hostname/ip address the server will bind to
                                                 [string] [default: "localhost"]
  --allowed-hosts       A comma-delimited string of hosts that are allowed to
                        access the dev server                           [string]

Options:
  --help, -h     Show help                                             [boolean]
  --version, -v  Show version number                                   [boolean]
  --bonjour      Broadcasts the server via ZeroConf networking on start[boolean]
  --lazy         Lazy                                                  [boolean]
  --inline       Inline mode (set to false to disable including client scripts
                 like livereload)                      [boolean] [default: true]
  --open         Open the default browser, or optionally specify a browser name
                                                                        [string]
  --useLocalIp   Open default browser with local IP                    [boolean]
  --open-page    Open default browser with the specified page           [string]

留意108~116行是有关连接的选项,简单翻译一下:

连接选项:
  --port                端口
  --disable-host-check  禁止检查主机端口                    [布尔值:true/false]
  --socket              用于监听的Socket
  --public              用于公共访问的域名或IP地址                      [字符串]
  --host                绑定到本机的域名或IP地址    [字符串] [缺省: "localhost"]
  --allowed-hosts       使用西文逗号分割的允许访问的主机域名或IP列表    [字符串]

由此,我们总算不用像实验一一样需要跑到代码中去修改eth服务的主机名那样麻烦了,直接可以通过webpack-dev-server指令的传参即可完成合约服务器的ip与端口的变更。

4. 修改package.json

回到项目目录,编辑package.json,将scriptes/dev的值修改为:"webpack-dev-server --host tru-host --public 192.168.3.103 --port 8088 --disable-host-check true",如下图:



5. 重新启动webpack合约服务器

truffle migrate
npm run dev

说明合约服务已正常启动。

(1) 验证本机服务访问:回到tru-host虚机,在浏览器上输入localhost:8080,可以发现访问失败了。原因是我们已把绑定的域名端口变为了http://tru-host:8088,尝试新的域名发现可以正常访问。



(2) 验证局域网其他机器的访问:在IP:192.168.3.36主机上访问http://192.168.3.103:8088,发现并没有出现像tru-host本机访问时出现的10000个MetaCoin币。



这是什么原因呢?原因是,我们确实在本地(192.168.3.36)没有任何的以太坊的账户,自然没办法从eth测试网络中获取账户余额并显示出来了。

(3) 安装MetaMask插件

为了进一步验证该服务是OK的,我们安装一个chrome插件:MetaMask,然后按指引完成账户的注册,ethereum网络会给大家生成一个免费的账户。

在登录的状态下点击下这个插件,左上角可以看到网络切换,选择”Custom RPC“并填入之前eth-host主机的IP地址和端口(http://192.168.3.102:8545),点击”save“保存eth网络设置;回到网络选择页面,选择刚才配置的eth网络。

   

然后回到插件主页面,选择”...“菜单,找到”copy Address to clipboard“



OK,现在我们已经在本地(192.168.3.36)通过已接入到我们的eth-host的eth网络可以查询账号余额了,并且我们通过MetaMask插件拷贝出了当前插件钱包中的eth账号了。


接下来,我们就往这个账号里面转2000个MetaCoin吧!

(4) 回到tru-host主机(当前仅仅这个主机账号上有10000个MetaCoin),在浏览器中”Amount“框里面填:2000;在下面的”To Address“的框里,粘贴刚才复制的账号,点击按键”Send MetaCoin“,可以看到在tru-host主机上执行转账成功了!



(5) 回到192.168.3.36主机上,在安装有MetaMask插件的浏览器上重新访问http://192.168.3.103:8088,可以发现我们已经有2000个MetaCoin了!



今天的实验就到此为止。总结下:

1. 回顾之前的truffle migrate操作,我们可以发现不仅仅做了eth网络的绑定还从eth网络中取回了第一个账本(上面有10000个MetaCoin)并将此账本写入到了项目中;

2. 可以通过package.json文件的scripts配置的指令,在./node_modules/.bin目录下找到执行的指令,并通过 --help 来获取传参并加以应用;

3. 智能合约的使用,需要账本的支持;而账本的支持,又要需要本地钱包的支撑。目前,钱包的形态也有很多种,像浏览器插件的方式可能是最轻量级的钱包应用了。

4. 其实完成了最后一步操作后,细心的朋友会发现我们的插件钱包MetaMask里面的ETH币值并未变化,还是零。我想可能是测试环境下并非产生真实币值是原因之一,此外,测试环境中缺乏挖矿节点形成51%的记账效果估计也是重要因素。


OK,就到这里,休息,休息一下!

祝大家国庆快乐!

猜你喜欢

转载自blog.csdn.net/xc70203/article/details/78144585