| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	testNodeKey, _ = crypto.GenerateKey() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | func testNodeConfig() *Config { | 
					
						
							|  |  |  | 	return &Config{ | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 		Name: "test node", | 
					
						
							|  |  |  | 		P2P:  p2p.Config{PrivateKey: testNodeKey}, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests that an empty protocol stack can be closed more than once. | 
					
						
							|  |  |  | func TestNodeCloseMultipleTimes(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	stack.Close() | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Ensure that a stopped node can be stopped again | 
					
						
							|  |  |  | 	for i := 0; i < 3; i++ { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if err := stack.Close(); err != ErrNodeStopped { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestNodeStartMultipleTimes(t *testing.T) { | 
					
						
							|  |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Ensure that a node can be successfully started, but only once | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := stack.Start(); err != ErrNodeRunning { | 
					
						
							|  |  |  | 		t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that a node can be stopped, but only once | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if err := stack.Close(); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("failed to stop node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if err := stack.Close(); err != ErrNodeStopped { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that if the data dir is already in use, an appropriate error is returned. | 
					
						
							|  |  |  | func TestNodeUsedDataDir(t *testing.T) { | 
					
						
							|  |  |  | 	// Create a temporary folder to use as the data directory | 
					
						
							|  |  |  | 	dir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temporary data directory: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a new node based on the data directory | 
					
						
							|  |  |  | 	original, err := New(&Config{DataDir: dir}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create original protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer original.Close() | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err := original.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start original protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a second node based on the same data directory and ensure failure | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	_, err = New(&Config{DataDir: dir}) | 
					
						
							|  |  |  | 	if err != ErrDatadirUsed { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests whether a Lifecycle can be registered. | 
					
						
							|  |  |  | func TestLifecycleRegistry_Successful(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	noop := NewNoop() | 
					
						
							|  |  |  | 	stack.RegisterLifecycle(noop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !containsLifecycle(stack.lifecycles, noop) { | 
					
						
							|  |  |  | 		t.Fatalf("lifecycle was not properly registered on the node, %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests whether a service's protocols can be registered properly on the node's p2p server. | 
					
						
							|  |  |  | func TestRegisterProtocols(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	fs, err := NewFullService(stack) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("could not create full service: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	for _, protocol := range fs.Protocols() { | 
					
						
							|  |  |  | 		if !containsProtocol(stack.server.Protocols, protocol) { | 
					
						
							|  |  |  | 			t.Fatalf("protocol %v was not successfully registered", protocol) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, api := range fs.APIs() { | 
					
						
							|  |  |  | 		if !containsAPI(stack.rpcAPIs, api) { | 
					
						
							|  |  |  | 			t.Fatalf("api %v was not successfully registered", api) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // This test checks that open databases are closed with node. | 
					
						
							|  |  |  | func TestNodeCloseClosesDB(t *testing.T) { | 
					
						
							|  |  |  | 	stack, _ := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	db, err := stack.OpenDatabase("mydb", 0, 0, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("can't open DB:", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if err = db.Put([]byte{}, []byte{}); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("can't Put on open DB:", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	stack.Close() | 
					
						
							|  |  |  | 	if err = db.Put([]byte{}, []byte{}); err == nil { | 
					
						
							|  |  |  | 		t.Fatal("Put succeeded after node is closed") | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // This test checks that OpenDatabase can be used from within a Lifecycle Start method. | 
					
						
							|  |  |  | func TestNodeOpenDatabaseFromLifecycleStart(t *testing.T) { | 
					
						
							|  |  |  | 	stack, _ := New(testNodeConfig()) | 
					
						
							|  |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var db ethdb.Database | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	stack.RegisterLifecycle(&InstrumentedService{ | 
					
						
							|  |  |  | 		startHook: func() { | 
					
						
							|  |  |  | 			db, err = stack.OpenDatabase("mydb", 0, 0, "") | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal("can't open DB:", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		stopHook: func() { | 
					
						
							|  |  |  | 			db.Close() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack.Start() | 
					
						
							|  |  |  | 	stack.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This test checks that OpenDatabase can be used from within a Lifecycle Stop method. | 
					
						
							|  |  |  | func TestNodeOpenDatabaseFromLifecycleStop(t *testing.T) { | 
					
						
							|  |  |  | 	stack, _ := New(testNodeConfig()) | 
					
						
							|  |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack.RegisterLifecycle(&InstrumentedService{ | 
					
						
							|  |  |  | 		stopHook: func() { | 
					
						
							|  |  |  | 			db, err := stack.OpenDatabase("mydb", 0, 0, "") | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal("can't open DB:", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			db.Close() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack.Start() | 
					
						
							|  |  |  | 	stack.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that registered Lifecycles get started and stopped correctly. | 
					
						
							|  |  |  | func TestLifecycleLifeCycle(t *testing.T) { | 
					
						
							|  |  |  | 	stack, _ := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a batch of instrumented services | 
					
						
							|  |  |  | 	lifecycles := map[string]Lifecycle{ | 
					
						
							|  |  |  | 		"A": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["A"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["A"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"B": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["B"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["B"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"C": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["C"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["C"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// register lifecycles on node | 
					
						
							|  |  |  | 	for _, lifecycle := range lifecycles { | 
					
						
							|  |  |  | 		stack.RegisterLifecycle(lifecycle) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the node and check that all services are running | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for id := range lifecycles { | 
					
						
							|  |  |  | 		if !started[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: freshly started service not running", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if stopped[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: freshly started service already stopped", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Stop the node and check that all services have been stopped | 
					
						
							|  |  |  | 	if err := stack.Close(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to stop protocol stack: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	for id := range lifecycles { | 
					
						
							|  |  |  | 		if !stopped[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: freshly terminated service still running", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests that if a Lifecycle fails to start, all others started before it will be | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // shut down. | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func TestLifecycleStartupError(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							|  |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Create a batch of instrumented services | 
					
						
							|  |  |  | 	lifecycles := map[string]Lifecycle{ | 
					
						
							|  |  |  | 		"A": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["A"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["A"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"B": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["B"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["B"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"C": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["C"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["C"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// register lifecycles on node | 
					
						
							|  |  |  | 	for _, lifecycle := range lifecycles { | 
					
						
							|  |  |  | 		stack.RegisterLifecycle(lifecycle) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Register a service that fails to construct itself | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	failure := errors.New("fail") | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	failer := &InstrumentedService{start: failure} | 
					
						
							|  |  |  | 	stack.RegisterLifecycle(failer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Start the protocol stack and ensure all started services stop | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if err := stack.Start(); err != failure { | 
					
						
							|  |  |  | 		t.Fatalf("stack startup failure mismatch: have %v, want %v", err, failure) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for id := range lifecycles { | 
					
						
							|  |  |  | 		if started[id] && !stopped[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: started but not stopped", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		delete(started, id) | 
					
						
							|  |  |  | 		delete(stopped, id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests that even if a registered Lifecycle fails to shut down cleanly, it does | 
					
						
							| 
									
										
										
										
											2020-05-25 16:21:28 +08:00
										 |  |  | // not influence the rest of the shutdown invocations. | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func TestLifecycleTerminationGuarantee(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 	defer stack.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							|  |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Create a batch of instrumented services | 
					
						
							|  |  |  | 	lifecycles := map[string]Lifecycle{ | 
					
						
							|  |  |  | 		"A": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["A"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["A"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"B": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["B"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["B"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"C": &InstrumentedService{ | 
					
						
							|  |  |  | 			startHook: func() { started["C"] = true }, | 
					
						
							|  |  |  | 			stopHook:  func() { stopped["C"] = true }, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// register lifecycles on node | 
					
						
							|  |  |  | 	for _, lifecycle := range lifecycles { | 
					
						
							|  |  |  | 		stack.RegisterLifecycle(lifecycle) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Register a service that fails to shot down cleanly | 
					
						
							|  |  |  | 	failure := errors.New("fail") | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	failer := &InstrumentedService{stop: failure} | 
					
						
							|  |  |  | 	stack.RegisterLifecycle(failer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Start the protocol stack, and ensure that a failing shut down terminates all | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Start the stack and make sure all is online | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for id := range lifecycles { | 
					
						
							|  |  |  | 		if !started[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: service not running", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if stopped[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: service already stopped", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Stop the stack, verify failure and check all terminations | 
					
						
							|  |  |  | 	err = stack.Close() | 
					
						
							|  |  |  | 	if err, ok := err.(*StopError); !ok { | 
					
						
							|  |  |  | 		t.Fatalf("termination failure mismatch: have %v, want StopError", err) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		failer := reflect.TypeOf(&InstrumentedService{}) | 
					
						
							|  |  |  | 		if err.Services[failer] != failure { | 
					
						
							|  |  |  | 			t.Fatalf("failer termination failure mismatch: have %v, want %v", err.Services[failer], failure) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if len(err.Services) != 1 { | 
					
						
							|  |  |  | 			t.Fatalf("failure count mismatch: have %d, want %d", len(err.Services), 1) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	for id := range lifecycles { | 
					
						
							|  |  |  | 		if !stopped[id] { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: service not terminated", id) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		delete(started, id) | 
					
						
							|  |  |  | 		delete(stopped, id) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack.server = &p2p.Server{} | 
					
						
							|  |  |  | 	stack.server.PrivateKey = testNodeKey | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests whether a handler can be successfully mounted on the canonical HTTP server | 
					
						
							|  |  |  | // on the given path | 
					
						
							|  |  |  | func TestRegisterHandler_Successful(t *testing.T) { | 
					
						
							|  |  |  | 	node := createNode(t, 7878, 7979) | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// create and mount handler | 
					
						
							|  |  |  | 	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 		w.Write([]byte("success")) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	node.RegisterHandler("test", "/test", handler) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// start node | 
					
						
							|  |  |  | 	if err := node.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("could not start node: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// create HTTP request | 
					
						
							|  |  |  | 	httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7878/test", nil) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Error("could not issue new http request ", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// check response | 
					
						
							|  |  |  | 	resp := doHTTPRequest(t, httpReq) | 
					
						
							|  |  |  | 	buf := make([]byte, 7) | 
					
						
							|  |  |  | 	_, err = io.ReadFull(resp.Body, buf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("could not read response: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	assert.Equal(t, "success", string(buf)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | // Tests that the given handler will not be successfully mounted since no HTTP server | 
					
						
							|  |  |  | // is enabled for RPC | 
					
						
							|  |  |  | func TestRegisterHandler_Unsuccessful(t *testing.T) { | 
					
						
							|  |  |  | 	node, err := New(&DefaultConfig) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Fatalf("could not create new node: %v", err) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-07 11:40:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// create and mount handler | 
					
						
							|  |  |  | 	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 		w.Write([]byte("success")) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	node.RegisterHandler("test", "/test", handler) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests whether websocket requests can be handled on the same port as a regular http server. | 
					
						
							|  |  |  | func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) { | 
					
						
							|  |  |  | 	node := startHTTP(t, 0, 0) | 
					
						
							|  |  |  | 	defer node.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ws := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if node.WSEndpoint() != ws { | 
					
						
							|  |  |  | 		t.Fatalf("endpoints should be the same") | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if !checkRPC(ws) { | 
					
						
							|  |  |  | 		t.Fatalf("ws request failed") | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if !checkRPC(node.HTTPEndpoint()) { | 
					
						
							|  |  |  | 		t.Fatalf("http request failed") | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func TestWebsocketHTTPOnSeparatePort_WSRequest(t *testing.T) { | 
					
						
							|  |  |  | 	// try and get a free port | 
					
						
							|  |  |  | 	listener, err := net.Listen("tcp", "127.0.0.1:0") | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Fatal("can't listen:", err) | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	port := listener.Addr().(*net.TCPAddr).Port | 
					
						
							|  |  |  | 	listener.Close() | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	node := startHTTP(t, 0, port) | 
					
						
							|  |  |  | 	defer node.Close() | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	wsOnHTTP := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) | 
					
						
							|  |  |  | 	ws := fmt.Sprintf("ws://127.0.0.1:%d", port) | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if node.WSEndpoint() == wsOnHTTP { | 
					
						
							|  |  |  | 		t.Fatalf("endpoints should not be the same") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// ensure ws endpoint matches the expected endpoint | 
					
						
							|  |  |  | 	if node.WSEndpoint() != ws { | 
					
						
							|  |  |  | 		t.Fatalf("ws endpoint is incorrect: expected %s, got %s", ws, node.WSEndpoint()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !checkRPC(ws) { | 
					
						
							|  |  |  | 		t.Fatalf("ws request failed") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !checkRPC(node.HTTPEndpoint()) { | 
					
						
							|  |  |  | 		t.Fatalf("http request failed") | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func createNode(t *testing.T, httpPort, wsPort int) *Node { | 
					
						
							|  |  |  | 	conf := &Config{ | 
					
						
							|  |  |  | 		HTTPHost: "127.0.0.1", | 
					
						
							|  |  |  | 		HTTPPort: httpPort, | 
					
						
							|  |  |  | 		WSHost:   "127.0.0.1", | 
					
						
							|  |  |  | 		WSPort:   wsPort, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	node, err := New(conf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Fatalf("could not create a new node: %v", err) | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	return node | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func startHTTP(t *testing.T, httpPort, wsPort int) *Node { | 
					
						
							|  |  |  | 	node := createNode(t, httpPort, wsPort) | 
					
						
							|  |  |  | 	err := node.Start() | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Fatalf("could not start http service on node: %v", err) | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return node | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	client := http.DefaultClient | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	resp, err := client.Do(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		t.Fatalf("could not issue a GET request to the given endpoint: %v", err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 13:33:12 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return resp | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool { | 
					
						
							|  |  |  | 	for _, a := range stackProtocols { | 
					
						
							|  |  |  | 		if reflect.DeepEqual(a, protocol) { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func containsAPI(stackAPIs []rpc.API, api rpc.API) bool { | 
					
						
							|  |  |  | 	for _, a := range stackAPIs { | 
					
						
							|  |  |  | 		if reflect.DeepEqual(a, api) { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } |