github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/node/node_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "errors" 21 "fmt" 22 "io" 23 "net" 24 "net/http" 25 "reflect" 26 "slices" 27 "strings" 28 "testing" 29 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/p2p" 33 "github.com/ethereum/go-ethereum/rpc" 34 35 "github.com/stretchr/testify/assert" 36 ) 37 38 var ( 39 testNodeKey, _ = crypto.GenerateKey() 40 ) 41 42 func testNodeConfig() *Config { 43 return &Config{ 44 Name: "test node", 45 P2P: p2p.Config{PrivateKey: testNodeKey}, 46 } 47 } 48 49 // Tests that an empty protocol stack can be closed more than once. 50 func TestNodeCloseMultipleTimes(t *testing.T) { 51 stack, err := New(testNodeConfig()) 52 if err != nil { 53 t.Fatalf("failed to create protocol stack: %v", err) 54 } 55 stack.Close() 56 57 // Ensure that a stopped node can be stopped again 58 for i := 0; i < 3; i++ { 59 if err := stack.Close(); err != ErrNodeStopped { 60 t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) 61 } 62 } 63 } 64 65 func TestNodeStartMultipleTimes(t *testing.T) { 66 stack, err := New(testNodeConfig()) 67 if err != nil { 68 t.Fatalf("failed to create protocol stack: %v", err) 69 } 70 71 // Ensure that a node can be successfully started, but only once 72 if err := stack.Start(); err != nil { 73 t.Fatalf("failed to start node: %v", err) 74 } 75 if err := stack.Start(); err != ErrNodeRunning { 76 t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) 77 } 78 // Ensure that a node can be stopped, but only once 79 if err := stack.Close(); err != nil { 80 t.Fatalf("failed to stop node: %v", err) 81 } 82 if err := stack.Close(); err != ErrNodeStopped { 83 t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) 84 } 85 } 86 87 // Tests that if the data dir is already in use, an appropriate error is returned. 88 func TestNodeUsedDataDir(t *testing.T) { 89 // Create a temporary folder to use as the data directory 90 dir := t.TempDir() 91 92 // Create a new node based on the data directory 93 original, err := New(&Config{DataDir: dir}) 94 if err != nil { 95 t.Fatalf("failed to create original protocol stack: %v", err) 96 } 97 defer original.Close() 98 if err := original.Start(); err != nil { 99 t.Fatalf("failed to start original protocol stack: %v", err) 100 } 101 102 // Create a second node based on the same data directory and ensure failure 103 _, err = New(&Config{DataDir: dir}) 104 if err != ErrDatadirUsed { 105 t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) 106 } 107 } 108 109 // Tests whether a Lifecycle can be registered. 110 func TestLifecycleRegistry_Successful(t *testing.T) { 111 stack, err := New(testNodeConfig()) 112 if err != nil { 113 t.Fatalf("failed to create protocol stack: %v", err) 114 } 115 defer stack.Close() 116 117 noop := NewNoop() 118 stack.RegisterLifecycle(noop) 119 120 if !slices.Contains(stack.lifecycles, Lifecycle(noop)) { 121 t.Fatalf("lifecycle was not properly registered on the node, %v", err) 122 } 123 } 124 125 // Tests whether a service's protocols can be registered properly on the node's p2p server. 126 func TestRegisterProtocols(t *testing.T) { 127 stack, err := New(testNodeConfig()) 128 if err != nil { 129 t.Fatalf("failed to create protocol stack: %v", err) 130 } 131 defer stack.Close() 132 133 fs, err := NewFullService(stack) 134 if err != nil { 135 t.Fatalf("could not create full service: %v", err) 136 } 137 138 for _, protocol := range fs.Protocols() { 139 if !containsProtocol(stack.server.Protocols, protocol) { 140 t.Fatalf("protocol %v was not successfully registered", protocol) 141 } 142 } 143 144 for _, api := range fs.APIs() { 145 if !containsAPI(stack.rpcAPIs, api) { 146 t.Fatalf("api %v was not successfully registered", api) 147 } 148 } 149 } 150 151 // This test checks that open databases are closed with node. 152 func TestNodeCloseClosesDB(t *testing.T) { 153 stack, _ := New(testNodeConfig()) 154 defer stack.Close() 155 156 db, err := stack.OpenDatabase("mydb", 0, 0, "", false) 157 if err != nil { 158 t.Fatal("can't open DB:", err) 159 } 160 if err = db.Put([]byte{}, []byte{}); err != nil { 161 t.Fatal("can't Put on open DB:", err) 162 } 163 164 stack.Close() 165 if err = db.Put([]byte{}, []byte{}); err == nil { 166 t.Fatal("Put succeeded after node is closed") 167 } 168 } 169 170 // This test checks that OpenDatabase can be used from within a Lifecycle Start method. 171 func TestNodeOpenDatabaseFromLifecycleStart(t *testing.T) { 172 stack, _ := New(testNodeConfig()) 173 defer stack.Close() 174 175 var db ethdb.Database 176 var err error 177 stack.RegisterLifecycle(&InstrumentedService{ 178 startHook: func() { 179 db, err = stack.OpenDatabase("mydb", 0, 0, "", false) 180 if err != nil { 181 t.Fatal("can't open DB:", err) 182 } 183 }, 184 stopHook: func() { 185 db.Close() 186 }, 187 }) 188 189 stack.Start() 190 stack.Close() 191 } 192 193 // This test checks that OpenDatabase can be used from within a Lifecycle Stop method. 194 func TestNodeOpenDatabaseFromLifecycleStop(t *testing.T) { 195 stack, _ := New(testNodeConfig()) 196 defer stack.Close() 197 198 stack.RegisterLifecycle(&InstrumentedService{ 199 stopHook: func() { 200 db, err := stack.OpenDatabase("mydb", 0, 0, "", false) 201 if err != nil { 202 t.Fatal("can't open DB:", err) 203 } 204 db.Close() 205 }, 206 }) 207 208 stack.Start() 209 stack.Close() 210 } 211 212 // Tests that registered Lifecycles get started and stopped correctly. 213 func TestLifecycleLifeCycle(t *testing.T) { 214 stack, _ := New(testNodeConfig()) 215 defer stack.Close() 216 217 started := make(map[string]bool) 218 stopped := make(map[string]bool) 219 220 // Create a batch of instrumented services 221 lifecycles := map[string]Lifecycle{ 222 "A": &InstrumentedService{ 223 startHook: func() { started["A"] = true }, 224 stopHook: func() { stopped["A"] = true }, 225 }, 226 "B": &InstrumentedService{ 227 startHook: func() { started["B"] = true }, 228 stopHook: func() { stopped["B"] = true }, 229 }, 230 "C": &InstrumentedService{ 231 startHook: func() { started["C"] = true }, 232 stopHook: func() { stopped["C"] = true }, 233 }, 234 } 235 // register lifecycles on node 236 for _, lifecycle := range lifecycles { 237 stack.RegisterLifecycle(lifecycle) 238 } 239 // Start the node and check that all services are running 240 if err := stack.Start(); err != nil { 241 t.Fatalf("failed to start protocol stack: %v", err) 242 } 243 for id := range lifecycles { 244 if !started[id] { 245 t.Fatalf("service %s: freshly started service not running", id) 246 } 247 if stopped[id] { 248 t.Fatalf("service %s: freshly started service already stopped", id) 249 } 250 } 251 // Stop the node and check that all services have been stopped 252 if err := stack.Close(); err != nil { 253 t.Fatalf("failed to stop protocol stack: %v", err) 254 } 255 for id := range lifecycles { 256 if !stopped[id] { 257 t.Fatalf("service %s: freshly terminated service still running", id) 258 } 259 } 260 } 261 262 // Tests that if a Lifecycle fails to start, all others started before it will be 263 // shut down. 264 func TestLifecycleStartupError(t *testing.T) { 265 stack, err := New(testNodeConfig()) 266 if err != nil { 267 t.Fatalf("failed to create protocol stack: %v", err) 268 } 269 defer stack.Close() 270 271 started := make(map[string]bool) 272 stopped := make(map[string]bool) 273 274 // Create a batch of instrumented services 275 lifecycles := map[string]Lifecycle{ 276 "A": &InstrumentedService{ 277 startHook: func() { started["A"] = true }, 278 stopHook: func() { stopped["A"] = true }, 279 }, 280 "B": &InstrumentedService{ 281 startHook: func() { started["B"] = true }, 282 stopHook: func() { stopped["B"] = true }, 283 }, 284 "C": &InstrumentedService{ 285 startHook: func() { started["C"] = true }, 286 stopHook: func() { stopped["C"] = true }, 287 }, 288 } 289 // register lifecycles on node 290 for _, lifecycle := range lifecycles { 291 stack.RegisterLifecycle(lifecycle) 292 } 293 294 // Register a service that fails to construct itself 295 failure := errors.New("fail") 296 failer := &InstrumentedService{start: failure} 297 stack.RegisterLifecycle(failer) 298 299 // Start the protocol stack and ensure all started services stop 300 if err := stack.Start(); err != failure { 301 t.Fatalf("stack startup failure mismatch: have %v, want %v", err, failure) 302 } 303 for id := range lifecycles { 304 if started[id] && !stopped[id] { 305 t.Fatalf("service %s: started but not stopped", id) 306 } 307 delete(started, id) 308 delete(stopped, id) 309 } 310 } 311 312 // Tests that even if a registered Lifecycle fails to shut down cleanly, it does 313 // not influence the rest of the shutdown invocations. 314 func TestLifecycleTerminationGuarantee(t *testing.T) { 315 stack, err := New(testNodeConfig()) 316 if err != nil { 317 t.Fatalf("failed to create protocol stack: %v", err) 318 } 319 defer stack.Close() 320 321 started := make(map[string]bool) 322 stopped := make(map[string]bool) 323 324 // Create a batch of instrumented services 325 lifecycles := map[string]Lifecycle{ 326 "A": &InstrumentedService{ 327 startHook: func() { started["A"] = true }, 328 stopHook: func() { stopped["A"] = true }, 329 }, 330 "B": &InstrumentedService{ 331 startHook: func() { started["B"] = true }, 332 stopHook: func() { stopped["B"] = true }, 333 }, 334 "C": &InstrumentedService{ 335 startHook: func() { started["C"] = true }, 336 stopHook: func() { stopped["C"] = true }, 337 }, 338 } 339 // register lifecycles on node 340 for _, lifecycle := range lifecycles { 341 stack.RegisterLifecycle(lifecycle) 342 } 343 344 // Register a service that fails to shot down cleanly 345 failure := errors.New("fail") 346 failer := &InstrumentedService{stop: failure} 347 stack.RegisterLifecycle(failer) 348 349 // Start the protocol stack, and ensure that a failing shut down terminates all 350 // Start the stack and make sure all is online 351 if err := stack.Start(); err != nil { 352 t.Fatalf("failed to start protocol stack: %v", err) 353 } 354 for id := range lifecycles { 355 if !started[id] { 356 t.Fatalf("service %s: service not running", id) 357 } 358 if stopped[id] { 359 t.Fatalf("service %s: service already stopped", id) 360 } 361 } 362 // Stop the stack, verify failure and check all terminations 363 err = stack.Close() 364 if err, ok := err.(*StopError); !ok { 365 t.Fatalf("termination failure mismatch: have %v, want StopError", err) 366 } else { 367 failer := reflect.TypeOf(&InstrumentedService{}) 368 if err.Services[failer] != failure { 369 t.Fatalf("failer termination failure mismatch: have %v, want %v", err.Services[failer], failure) 370 } 371 if len(err.Services) != 1 { 372 t.Fatalf("failure count mismatch: have %d, want %d", len(err.Services), 1) 373 } 374 } 375 for id := range lifecycles { 376 if !stopped[id] { 377 t.Fatalf("service %s: service not terminated", id) 378 } 379 delete(started, id) 380 delete(stopped, id) 381 } 382 383 stack.server = &p2p.Server{} 384 stack.server.PrivateKey = testNodeKey 385 } 386 387 // Tests whether a handler can be successfully mounted on the canonical HTTP server 388 // on the given prefix 389 func TestRegisterHandler_Successful(t *testing.T) { 390 node := createNode(t, 7878, 7979) 391 defer node.Close() 392 // create and mount handler 393 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 394 w.Write([]byte("success")) 395 }) 396 node.RegisterHandler("test", "/test", handler) 397 398 // start node 399 if err := node.Start(); err != nil { 400 t.Fatalf("could not start node: %v", err) 401 } 402 403 // create HTTP request 404 httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7878/test", nil) 405 if err != nil { 406 t.Error("could not issue new http request ", err) 407 } 408 409 // check response 410 resp := doHTTPRequest(t, httpReq) 411 buf := make([]byte, 7) 412 _, err = io.ReadFull(resp.Body, buf) 413 if err != nil { 414 t.Fatalf("could not read response: %v", err) 415 } 416 assert.Equal(t, "success", string(buf)) 417 } 418 419 // Tests whether websocket requests can be handled on the same port as a regular http server. 420 func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) { 421 node := startHTTP(t, 0, 0) 422 defer node.Close() 423 424 ws := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) 425 426 if node.WSEndpoint() != ws { 427 t.Fatalf("endpoints should be the same") 428 } 429 if !checkRPC(ws) { 430 t.Fatalf("ws request failed") 431 } 432 if !checkRPC(node.HTTPEndpoint()) { 433 t.Fatalf("http request failed") 434 } 435 } 436 437 func TestWebsocketHTTPOnSeparatePort_WSRequest(t *testing.T) { 438 // try and get a free port 439 listener, err := net.Listen("tcp", "127.0.0.1:0") 440 if err != nil { 441 t.Fatal("can't listen:", err) 442 } 443 port := listener.Addr().(*net.TCPAddr).Port 444 listener.Close() 445 446 node := startHTTP(t, 0, port) 447 defer node.Close() 448 449 wsOnHTTP := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) 450 ws := fmt.Sprintf("ws://127.0.0.1:%d", port) 451 452 if node.WSEndpoint() == wsOnHTTP { 453 t.Fatalf("endpoints should not be the same") 454 } 455 // ensure ws endpoint matches the expected endpoint 456 if node.WSEndpoint() != ws { 457 t.Fatalf("ws endpoint is incorrect: expected %s, got %s", ws, node.WSEndpoint()) 458 } 459 460 if !checkRPC(ws) { 461 t.Fatalf("ws request failed") 462 } 463 if !checkRPC(node.HTTPEndpoint()) { 464 t.Fatalf("http request failed") 465 } 466 } 467 468 type rpcPrefixTest struct { 469 httpPrefix, wsPrefix string 470 // These lists paths on which JSON-RPC should be served / not served. 471 wantHTTP []string 472 wantNoHTTP []string 473 wantWS []string 474 wantNoWS []string 475 } 476 477 func TestNodeRPCPrefix(t *testing.T) { 478 t.Parallel() 479 480 tests := []rpcPrefixTest{ 481 // both off 482 { 483 httpPrefix: "", wsPrefix: "", 484 wantHTTP: []string{"/", "/?p=1"}, 485 wantNoHTTP: []string{"/test", "/test?p=1"}, 486 wantWS: []string{"/", "/?p=1"}, 487 wantNoWS: []string{"/test", "/test?p=1"}, 488 }, 489 // only http prefix 490 { 491 httpPrefix: "/testprefix", wsPrefix: "", 492 wantHTTP: []string{"/testprefix", "/testprefix?p=1", "/testprefix/x", "/testprefix/x?p=1"}, 493 wantNoHTTP: []string{"/", "/?p=1", "/test", "/test?p=1"}, 494 wantWS: []string{"/", "/?p=1"}, 495 wantNoWS: []string{"/testprefix", "/testprefix?p=1", "/test", "/test?p=1"}, 496 }, 497 // only ws prefix 498 { 499 httpPrefix: "", wsPrefix: "/testprefix", 500 wantHTTP: []string{"/", "/?p=1"}, 501 wantNoHTTP: []string{"/testprefix", "/testprefix?p=1", "/test", "/test?p=1"}, 502 wantWS: []string{"/testprefix", "/testprefix?p=1", "/testprefix/x", "/testprefix/x?p=1"}, 503 wantNoWS: []string{"/", "/?p=1", "/test", "/test?p=1"}, 504 }, 505 // both set 506 { 507 httpPrefix: "/testprefix", wsPrefix: "/testprefix", 508 wantHTTP: []string{"/testprefix", "/testprefix?p=1", "/testprefix/x", "/testprefix/x?p=1"}, 509 wantNoHTTP: []string{"/", "/?p=1", "/test", "/test?p=1"}, 510 wantWS: []string{"/testprefix", "/testprefix?p=1", "/testprefix/x", "/testprefix/x?p=1"}, 511 wantNoWS: []string{"/", "/?p=1", "/test", "/test?p=1"}, 512 }, 513 } 514 515 for _, test := range tests { 516 test := test 517 name := fmt.Sprintf("http=%s ws=%s", test.httpPrefix, test.wsPrefix) 518 t.Run(name, func(t *testing.T) { 519 cfg := &Config{ 520 HTTPHost: "127.0.0.1", 521 HTTPPathPrefix: test.httpPrefix, 522 WSHost: "127.0.0.1", 523 WSPathPrefix: test.wsPrefix, 524 } 525 node, err := New(cfg) 526 if err != nil { 527 t.Fatal("can't create node:", err) 528 } 529 defer node.Close() 530 if err := node.Start(); err != nil { 531 t.Fatal("can't start node:", err) 532 } 533 test.check(t, node) 534 }) 535 } 536 } 537 538 func (test rpcPrefixTest) check(t *testing.T, node *Node) { 539 t.Helper() 540 httpBase := "http://" + node.http.listenAddr() 541 wsBase := "ws://" + node.http.listenAddr() 542 543 if node.WSEndpoint() != wsBase+test.wsPrefix { 544 t.Errorf("Error: node has wrong WSEndpoint %q", node.WSEndpoint()) 545 } 546 547 for _, path := range test.wantHTTP { 548 resp := rpcRequest(t, httpBase+path, testMethod) 549 if resp.StatusCode != 200 { 550 t.Errorf("Error: %s: bad status code %d, want 200", path, resp.StatusCode) 551 } 552 } 553 for _, path := range test.wantNoHTTP { 554 resp := rpcRequest(t, httpBase+path, testMethod) 555 if resp.StatusCode != 404 { 556 t.Errorf("Error: %s: bad status code %d, want 404", path, resp.StatusCode) 557 } 558 } 559 for _, path := range test.wantWS { 560 err := wsRequest(t, wsBase+path) 561 if err != nil { 562 t.Errorf("Error: %s: WebSocket connection failed: %v", path, err) 563 } 564 } 565 for _, path := range test.wantNoWS { 566 err := wsRequest(t, wsBase+path) 567 if err == nil { 568 t.Errorf("Error: %s: WebSocket connection succeeded for path in wantNoWS", path) 569 } 570 } 571 } 572 573 func createNode(t *testing.T, httpPort, wsPort int) *Node { 574 conf := &Config{ 575 HTTPHost: "127.0.0.1", 576 HTTPPort: httpPort, 577 WSHost: "127.0.0.1", 578 WSPort: wsPort, 579 HTTPTimeouts: rpc.DefaultHTTPTimeouts, 580 } 581 node, err := New(conf) 582 if err != nil { 583 t.Fatalf("could not create a new node: %v", err) 584 } 585 return node 586 } 587 588 func startHTTP(t *testing.T, httpPort, wsPort int) *Node { 589 node := createNode(t, httpPort, wsPort) 590 err := node.Start() 591 if err != nil { 592 t.Fatalf("could not start http service on node: %v", err) 593 } 594 595 return node 596 } 597 598 func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { 599 client := http.DefaultClient 600 resp, err := client.Do(req) 601 if err != nil { 602 t.Fatalf("could not issue a GET request to the given endpoint: %v", err) 603 } 604 t.Cleanup(func() { resp.Body.Close() }) 605 return resp 606 } 607 608 func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool { 609 for _, a := range stackProtocols { 610 if reflect.DeepEqual(a, protocol) { 611 return true 612 } 613 } 614 return false 615 } 616 617 func containsAPI(stackAPIs []rpc.API, api rpc.API) bool { 618 for _, a := range stackAPIs { 619 if reflect.DeepEqual(a, api) { 620 return true 621 } 622 } 623 return false 624 }