在CENTOS7上玩轉Ethereum區塊鏈(6):實驗二–對外發布智慧合約服務

在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,就到這裡,休息,休息一下!

祝大家國慶快樂!