@@ -30,108 +30,86 @@ import (
30
30
31
31
// explorerDockerfile is the Dockerfile required to run a block explorer.
32
32
var explorerDockerfile = `
33
- FROM puppeth/explorer:latest
34
-
35
- ADD ethstats.json /ethstats.json
36
- ADD chain.json /chain.json
33
+ FROM puppeth/blockscout:latest
37
34
35
+ ADD genesis.json /genesis.json
38
36
RUN \
39
- echo '(cd ../eth-net-intelligence-api && pm2 start /ethstats.json)' > explorer.sh && \
40
- echo '(cd ../etherchain-light && npm start &)' >> explorer.sh && \
41
- echo 'exec /parity/parity --chain=/chain.json --port={{.NodePort}} --tracing=on --fat-db=on --pruning=archive' >> explorer.sh
37
+ echo 'geth --cache 512 init /genesis.json' > explorer.sh && \
38
+ echo $'geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcapi "net,web3,eth,shh,debug" --rpccorsdomain "*" --rpcvhosts "*" --ws --wsorigins "*" --exitwhensynced' >> explorer.sh && \
39
+ echo $'exec geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcapi "net,web3,eth,shh,debug" --rpccorsdomain "*" --rpcvhosts "*" --ws --wsorigins "*" &' >> explorer.sh && \
40
+ echo '/usr/local/bin/docker-entrypoint.sh postgres &' >> explorer.sh && \
41
+ echo 'sleep 5' >> explorer.sh && \
42
+ echo 'mix do ecto.drop --force, ecto.create, ecto.migrate' >> explorer.sh && \
43
+ echo 'mix phx.server' >> explorer.sh
42
44
43
45
ENTRYPOINT ["/bin/sh", "explorer.sh"]
44
46
`
45
47
46
- // explorerEthstats is the configuration file for the ethstats javascript client.
47
- var explorerEthstats = `[
48
- {
49
- "name" : "node-app",
50
- "script" : "app.js",
51
- "log_date_format" : "YYYY-MM-DD HH:mm Z",
52
- "merge_logs" : false,
53
- "watch" : false,
54
- "max_restarts" : 10,
55
- "exec_interpreter" : "node",
56
- "exec_mode" : "fork_mode",
57
- "env":
58
- {
59
- "NODE_ENV" : "production",
60
- "RPC_HOST" : "localhost",
61
- "RPC_PORT" : "8545",
62
- "LISTENING_PORT" : "{{.Port}}",
63
- "INSTANCE_NAME" : "{{.Name}}",
64
- "CONTACT_DETAILS" : "",
65
- "WS_SERVER" : "{{.Host}}",
66
- "WS_SECRET" : "{{.Secret}}",
67
- "VERBOSITY" : 2
68
- }
69
- }
70
- ]`
71
-
72
48
// explorerComposefile is the docker-compose.yml file required to deploy and
73
49
// maintain a block explorer.
74
50
var explorerComposefile = `
75
51
version: '2'
76
52
services:
77
- explorer:
78
- build: .
79
- image: {{.Network}}/explorer
80
- container_name: {{.Network}}_explorer_1
81
- ports:
82
- - "{{.NodePort}}:{{.NodePort}}"
83
- - "{{.NodePort}}:{{.NodePort}}/udp"{{if not .VHost}}
84
- - "{{.WebPort}}:3000"{{end}}
85
- volumes:
86
- - {{.Datadir}}:/root/.local/share/io.parity.ethereum
87
- environment:
88
- - NODE_PORT={{.NodePort}}/tcp
89
- - STATS={{.Ethstats}}{{if .VHost}}
90
- - VIRTUAL_HOST={{.VHost}}
91
- - VIRTUAL_PORT=3000{{end}}
92
- logging:
93
- driver: "json-file"
94
- options:
95
- max-size: "1m"
96
- max-file: "10"
97
- restart: always
53
+ explorer:
54
+ build: .
55
+ image: {{.Network}}/explorer
56
+ container_name: {{.Network}}_explorer_1
57
+ ports:
58
+ - "{{.EthPort}}:{{.EthPort}}"
59
+ - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}}
60
+ - "{{.WebPort}}:4000"{{end}}
61
+ environment:
62
+ - ETH_PORT={{.EthPort}}
63
+ - ETH_NAME={{.EthName}}
64
+ - BLOCK_TRANSFORMER={{.Transformer}}{{if .VHost}}
65
+ - VIRTUAL_HOST={{.VHost}}
66
+ - VIRTUAL_PORT=4000{{end}}
67
+ volumes:
68
+ - {{.Datadir}}:/opt/app/.ethereum
69
+ - {{.DBDir}}:/var/lib/postgresql/data
70
+ logging:
71
+ driver: "json-file"
72
+ options:
73
+ max-size: "1m"
74
+ max-file: "10"
75
+ restart: always
98
76
`
99
77
100
78
// deployExplorer deploys a new block explorer container to a remote machine via
101
79
// SSH, docker and docker-compose. If an instance with the specified network name
102
80
// already exists there, it will be overwritten!
103
- func deployExplorer (client * sshClient , network string , chainspec []byte , config * explorerInfos , nocache bool ) ([]byte , error ) {
81
+ func deployExplorer (client * sshClient , network string , bootnodes []string , config * explorerInfos , nocache bool , isClique bool ) ([]byte , error ) {
104
82
// Generate the content to upload to the server
105
83
workdir := fmt .Sprintf ("%d" , rand .Int63 ())
106
84
files := make (map [string ][]byte )
107
85
108
86
dockerfile := new (bytes.Buffer )
109
87
template .Must (template .New ("" ).Parse (explorerDockerfile )).Execute (dockerfile , map [string ]interface {}{
110
- "NodePort" : config .nodePort ,
88
+ "NetworkID" : config .node .network ,
89
+ "Bootnodes" : strings .Join (bootnodes , "," ),
90
+ "Ethstats" : config .node .ethstats ,
91
+ "EthPort" : config .node .port ,
111
92
})
112
93
files [filepath .Join (workdir , "Dockerfile" )] = dockerfile .Bytes ()
113
94
114
- ethstats := new (bytes.Buffer )
115
- template .Must (template .New ("" ).Parse (explorerEthstats )).Execute (ethstats , map [string ]interface {}{
116
- "Port" : config .nodePort ,
117
- "Name" : config .ethstats [:strings .Index (config .ethstats , ":" )],
118
- "Secret" : config .ethstats [strings .Index (config .ethstats , ":" )+ 1 : strings .Index (config .ethstats , "@" )],
119
- "Host" : config .ethstats [strings .Index (config .ethstats , "@" )+ 1 :],
120
- })
121
- files [filepath .Join (workdir , "ethstats.json" )] = ethstats .Bytes ()
122
-
95
+ transformer := "base"
96
+ if isClique {
97
+ transformer = "clique"
98
+ }
123
99
composefile := new (bytes.Buffer )
124
100
template .Must (template .New ("" ).Parse (explorerComposefile )).Execute (composefile , map [string ]interface {}{
125
- "Datadir" : config .datadir ,
126
- "Network" : network ,
127
- "NodePort" : config .nodePort ,
128
- "VHost" : config .webHost ,
129
- "WebPort" : config .webPort ,
130
- "Ethstats" : config .ethstats [:strings .Index (config .ethstats , ":" )],
101
+ "Network" : network ,
102
+ "VHost" : config .host ,
103
+ "Ethstats" : config .node .ethstats ,
104
+ "Datadir" : config .node .datadir ,
105
+ "DBDir" : config .dbdir ,
106
+ "EthPort" : config .node .port ,
107
+ "EthName" : config .node .ethstats [:strings .Index (config .node .ethstats , ":" )],
108
+ "WebPort" : config .port ,
109
+ "Transformer" : transformer ,
131
110
})
132
111
files [filepath .Join (workdir , "docker-compose.yaml" )] = composefile .Bytes ()
133
-
134
- files [filepath .Join (workdir , "chain.json" )] = chainspec
112
+ files [filepath .Join (workdir , "genesis.json" )] = config .node .genesis
135
113
136
114
// Upload the deployment files to the remote server (and clean up afterwards)
137
115
if out , err := client .Upload (files ); err != nil {
@@ -149,30 +127,28 @@ func deployExplorer(client *sshClient, network string, chainspec []byte, config
149
127
// explorerInfos is returned from a block explorer status check to allow reporting
150
128
// various configuration parameters.
151
129
type explorerInfos struct {
152
- datadir string
153
- ethstats string
154
- nodePort int
155
- webHost string
156
- webPort int
130
+ node * nodeInfos
131
+ dbdir string
132
+ host string
133
+ port int
157
134
}
158
135
159
136
// Report converts the typed struct into a plain string->string map, containing
160
137
// most - but not all - fields for reporting to the user.
161
138
func (info * explorerInfos ) Report () map [string ]string {
162
139
report := map [string ]string {
163
- "Data directory" : info .datadir ,
164
- "Node listener port " : strconv .Itoa (info .nodePort ),
165
- "Ethstats username" : info .ethstats ,
166
- "Website address " : info .webHost ,
167
- "Website listener port " : strconv .Itoa (info .webPort ),
140
+ "Website address " : info .host ,
141
+ "Website listener port " : strconv .Itoa (info .port ),
142
+ "Ethereum listener port " : strconv .Itoa (info .node .port ),
143
+ "Ethstats username" : info .node .ethstats ,
168
144
}
169
145
return report
170
146
}
171
147
172
148
// checkExplorer does a health-check against a block explorer server to verify
173
149
// whether it's running, and if yes, whether it's responsive.
174
150
func checkExplorer (client * sshClient , network string ) (* explorerInfos , error ) {
175
- // Inspect a possible block explorer container on the host
151
+ // Inspect a possible explorer container on the host
176
152
infos , err := inspectContainer (client , fmt .Sprintf ("%s_explorer_1" , network ))
177
153
if err != nil {
178
154
return nil , err
@@ -181,13 +157,13 @@ func checkExplorer(client *sshClient, network string) (*explorerInfos, error) {
181
157
return nil , ErrServiceOffline
182
158
}
183
159
// Resolve the port from the host, or the reverse proxy
184
- webPort := infos .portmap ["3000 /tcp" ]
185
- if webPort == 0 {
160
+ port := infos .portmap ["4000 /tcp" ]
161
+ if port == 0 {
186
162
if proxy , _ := checkNginx (client , network ); proxy != nil {
187
- webPort = proxy .port
163
+ port = proxy .port
188
164
}
189
165
}
190
- if webPort == 0 {
166
+ if port == 0 {
191
167
return nil , ErrNotExposed
192
168
}
193
169
// Resolve the host from the reverse-proxy and the config values
@@ -196,17 +172,23 @@ func checkExplorer(client *sshClient, network string) (*explorerInfos, error) {
196
172
host = client .server
197
173
}
198
174
// Run a sanity check to see if the devp2p is reachable
199
- nodePort := infos .portmap [infos .envvars ["NODE_PORT" ]]
200
- if err = checkPort (client .server , nodePort ); err != nil {
201
- log .Warn (fmt .Sprintf ("Explorer devp2p port seems unreachable" ), "server" , client .server , "port" , nodePort , "err" , err )
175
+ p2pPort := infos .portmap [infos .envvars ["ETH_PORT" ]+ "/tcp" ]
176
+ if err = checkPort (host , p2pPort ); err != nil {
177
+ log .Warn ("Explorer node seems unreachable" , "server" , host , "port" , p2pPort , "err" , err )
178
+ }
179
+ if err = checkPort (host , port ); err != nil {
180
+ log .Warn ("Explorer service seems unreachable" , "server" , host , "port" , port , "err" , err )
202
181
}
203
182
// Assemble and return the useful infos
204
183
stats := & explorerInfos {
205
- datadir : infos .volumes ["/root/.local/share/io.parity.ethereum" ],
206
- nodePort : nodePort ,
207
- webHost : host ,
208
- webPort : webPort ,
209
- ethstats : infos .envvars ["STATS" ],
184
+ node : & nodeInfos {
185
+ datadir : infos .volumes ["/opt/app/.ethereum" ],
186
+ port : infos .portmap [infos .envvars ["ETH_PORT" ]+ "/tcp" ],
187
+ ethstats : infos .envvars ["ETH_NAME" ],
188
+ },
189
+ dbdir : infos .volumes ["/var/lib/postgresql/data" ],
190
+ host : host ,
191
+ port : port ,
210
192
}
211
193
return stats , nil
212
194
}
0 commit comments