github.com/ConsenSys/Quorum@v20.10.0+incompatible/cmd/geth/consolecmd_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "crypto/rand" 21 "crypto/tls" 22 "flag" 23 "io/ioutil" 24 "math/big" 25 "os" 26 "path/filepath" 27 "runtime" 28 "strconv" 29 "strings" 30 "testing" 31 "time" 32 33 "github.com/ethereum/go-ethereum/cmd/utils" 34 "github.com/ethereum/go-ethereum/params" 35 testifyassert "github.com/stretchr/testify/assert" 36 "gopkg.in/urfave/cli.v1" 37 ) 38 39 const ( 40 ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" 41 httpAPIs = "admin:1.0 eth:1.0 net:1.0 rpc:1.0 web3:1.0" 42 nodeKey = "b68c0338aa4b266bf38ebe84c6199ae9fac8b29f32998b3ed2fbeafebe8d65c9" 43 ) 44 45 var genesis = `{ 46 "config": { 47 "chainId": 2017, 48 "homesteadBlock": 1, 49 "eip150Block": 2, 50 "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 51 "eip155Block": 3, 52 "eip158Block": 3, 53 "istanbul": { 54 "epoch": 30000, 55 "policy": 0 56 } 57 }, 58 "nonce": "0x0", 59 "timestamp": "0x0", 60 "gasLimit": "0x47b760", 61 "difficulty": "0x1", 62 "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365", 63 "coinbase": "0x0000000000000000000000000000000000000000", 64 "alloc": { 65 "491937757d1b26e29c507b8d4c0b233c2747e68d": { 66 "balance": "0x446c3b15f9926687d2c40534fdb564000000000000" 67 } 68 }, 69 "number": "0x0", 70 "gasUsed": "0x0", 71 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" 72 } 73 ` 74 75 // Tests that a node embedded within a console can be started up properly and 76 // then terminated by closing the input stream. 77 func TestConsoleWelcome(t *testing.T) { 78 defer SetResetPrivateConfig("ignore")() 79 coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" 80 81 datadir := setupIstanbul(t) 82 defer os.RemoveAll(datadir) 83 84 // Start a geth console, make sure it's cleaned up and terminate the console 85 geth := runGeth(t, 86 "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", 87 "--etherbase", coinbase, "--shh", 88 "console") 89 90 // Gather all the infos the welcome message needs to contain 91 geth.SetTemplateFunc("goos", func() string { return runtime.GOOS }) 92 geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) 93 geth.SetTemplateFunc("gover", runtime.Version) 94 geth.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) 95 geth.SetTemplateFunc("quorumver", func() string { return params.QuorumVersion }) 96 geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) 97 geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) 98 99 // Verify the actual welcome message to the required template 100 geth.Expect(` 101 Welcome to the Geth JavaScript console! 102 103 instance: Geth/v{{gethver}}(quorum-v{{quorumver}})/{{goos}}-{{goarch}}/{{gover}} 104 coinbase: {{.Etherbase}} 105 at block: 0 ({{niltime}}) 106 datadir: {{.Datadir}} 107 modules: {{apis}} 108 109 > {{.InputLine "exit"}} 110 `) 111 geth.ExpectExit() 112 } 113 114 // Tests that a console can be attached to a running node via various means. 115 func TestIPCAttachWelcome(t *testing.T) { 116 defer SetResetPrivateConfig("ignore")() 117 // Configure the instance for IPC attachement 118 coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" 119 var ipc string 120 121 datadir := setupIstanbul(t) 122 defer os.RemoveAll(datadir) 123 124 if runtime.GOOS == "windows" { 125 ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999)) 126 } else { 127 ipc = filepath.Join(datadir, "geth.ipc") 128 } 129 130 // Note: we need --shh because testAttachWelcome checks for default 131 // list of ipc modules and shh is included there. 132 geth := runGeth(t, 133 "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", 134 "--etherbase", coinbase, "--shh", "--ipcpath", ipc) 135 136 waitForEndpoint(t, ipc, 3*time.Second) 137 testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs) 138 139 geth.Interrupt() 140 geth.ExpectExit() 141 } 142 143 func TestHTTPAttachWelcome(t *testing.T) { 144 defer SetResetPrivateConfig("ignore")() 145 coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" 146 port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P 147 148 datadir := setupIstanbul(t) 149 defer os.RemoveAll(datadir) 150 151 geth := runGeth(t, 152 "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", 153 "--etherbase", coinbase, "--rpc", "--rpcport", port, "--rpcapi", "admin,eth,net,web3") 154 155 endpoint := "http://127.0.0.1:" + port 156 waitForEndpoint(t, endpoint, 3*time.Second) 157 testAttachWelcome(t, geth, endpoint, httpAPIs) 158 159 geth.Interrupt() 160 geth.ExpectExit() 161 } 162 163 func TestWSAttachWelcome(t *testing.T) { 164 defer SetResetPrivateConfig("ignore")() 165 coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" 166 port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P 167 168 datadir := setupIstanbul(t) 169 defer os.RemoveAll(datadir) 170 171 geth := runGeth(t, 172 "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", 173 "--etherbase", coinbase, "--ws", "--wsport", port, "--wsapi", "admin,eth,net,web3") 174 175 endpoint := "ws://127.0.0.1:" + port 176 waitForEndpoint(t, endpoint, 3*time.Second) 177 testAttachWelcome(t, geth, endpoint, httpAPIs) 178 179 geth.Interrupt() 180 geth.ExpectExit() 181 } 182 183 func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { 184 // Attach to a running geth note and terminate immediately 185 attach := runGeth(t, "attach", endpoint) 186 defer attach.ExpectExit() 187 attach.CloseStdin() 188 189 // Gather all the infos the welcome message needs to contain 190 attach.SetTemplateFunc("goos", func() string { return runtime.GOOS }) 191 attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) 192 attach.SetTemplateFunc("gover", runtime.Version) 193 attach.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) 194 attach.SetTemplateFunc("quorumver", func() string { return params.QuorumVersion }) 195 attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase }) 196 attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) 197 attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") || strings.Contains(apis, "admin") }) 198 attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) 199 attach.SetTemplateFunc("apis", func() string { return apis }) 200 201 // Verify the actual welcome message to the required template 202 attach.Expect(` 203 Welcome to the Geth JavaScript console! 204 205 instance: Geth/v{{gethver}}(quorum-v{{quorumver}})/{{goos}}-{{goarch}}/{{gover}} 206 coinbase: {{etherbase}} 207 at block: 0 ({{niltime}}){{if ipc}} 208 datadir: {{datadir}}{{end}} 209 modules: {{apis}} 210 211 > {{.InputLine "exit" }} 212 `) 213 attach.ExpectExit() 214 } 215 216 // trulyRandInt generates a crypto random integer used by the console tests to 217 // not clash network ports with other tests running cocurrently. 218 func trulyRandInt(lo, hi int) int { 219 num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo))) 220 return int(num.Int64()) + lo 221 } 222 223 // setupIstanbul creates a temporary directory and copies nodekey and genesis.json. 224 // It initializes istanbul by calling geth init 225 func setupIstanbul(t *testing.T) string { 226 datadir := tmpdir(t) 227 gethPath := filepath.Join(datadir, "geth") 228 os.Mkdir(gethPath, 0700) 229 230 // Initialize the data directory with the custom genesis block 231 json := filepath.Join(datadir, "genesis.json") 232 if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil { 233 t.Fatalf("failed to write genesis file: %v", err) 234 } 235 236 nodeKeyFile := filepath.Join(gethPath, "nodekey") 237 if err := ioutil.WriteFile(nodeKeyFile, []byte(nodeKey), 0600); err != nil { 238 t.Fatalf("failed to write nodekey file: %v", err) 239 } 240 241 runGeth(t, "--datadir", datadir, "init", json).WaitExit() 242 243 return datadir 244 } 245 246 func TestReadTLSClientConfig_whenCustomizeTLSCipherSuites(t *testing.T) { 247 assert := testifyassert.New(t) 248 249 flagSet := new(flag.FlagSet) 250 flagSet.Bool(utils.RPCClientTLSInsecureSkipVerify.Name, true, "") 251 flagSet.String(utils.RPCClientTLSCipherSuites.Name, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "") 252 ctx := cli.NewContext(nil, flagSet, nil) 253 254 tlsConf, ok, err := readTLSClientConfig("https://arbitraryendpoint", ctx) 255 256 assert.NoError(err) 257 assert.True(ok, "has custom TLS client configuration") 258 assert.True(tlsConf.InsecureSkipVerify) 259 assert.Len(tlsConf.CipherSuites, 2) 260 assert.Contains(tlsConf.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) 261 assert.Contains(tlsConf.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) 262 } 263 264 func TestReadTLSClientConfig_whenTypicalTLS(t *testing.T) { 265 assert := testifyassert.New(t) 266 267 flagSet := new(flag.FlagSet) 268 ctx := cli.NewContext(nil, flagSet, nil) 269 270 tlsConf, ok, err := readTLSClientConfig("https://arbitraryendpoint", ctx) 271 272 assert.NoError(err) 273 assert.False(ok, "no custom TLS client configuration") 274 assert.Nil(tlsConf, "no custom TLS config is set") 275 } 276 277 func TestReadTLSClientConfig_whenTLSInsecureFlagSet(t *testing.T) { 278 assert := testifyassert.New(t) 279 280 flagSet := new(flag.FlagSet) 281 flagSet.Bool(utils.RPCClientTLSInsecureSkipVerify.Name, true, "") 282 ctx := cli.NewContext(nil, flagSet, nil) 283 284 tlsConf, ok, err := readTLSClientConfig("https://arbitraryendpoint", ctx) 285 286 assert.NoError(err) 287 assert.True(ok, "has custom TLS client configuration") 288 assert.True(tlsConf.InsecureSkipVerify) 289 assert.Len(tlsConf.CipherSuites, 0) 290 } 291 292 func SetResetPrivateConfig(value string) func() { 293 existingValue := os.Getenv("PRIVATE_CONFIG") 294 os.Setenv("PRIVATE_CONFIG", value) 295 return func() { 296 os.Setenv("PRIVATE_CONFIG", existingValue) 297 } 298 }