github.com/snowblossomcoin/go-ethereum@v1.9.25/cmd/geth/les_test.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"path/filepath"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ethereum/go-ethereum/p2p"
    10  	"github.com/ethereum/go-ethereum/rpc"
    11  )
    12  
    13  type gethrpc struct {
    14  	name     string
    15  	rpc      *rpc.Client
    16  	geth     *testgeth
    17  	nodeInfo *p2p.NodeInfo
    18  }
    19  
    20  func (g *gethrpc) killAndWait() {
    21  	g.geth.Kill()
    22  	g.geth.WaitExit()
    23  }
    24  
    25  func (g *gethrpc) callRPC(result interface{}, method string, args ...interface{}) {
    26  	if err := g.rpc.Call(&result, method, args...); err != nil {
    27  		g.geth.Fatalf("callRPC %v: %v", method, err)
    28  	}
    29  }
    30  
    31  func (g *gethrpc) addPeer(peer *gethrpc) {
    32  	g.geth.Logf("%v.addPeer(%v)", g.name, peer.name)
    33  	enode := peer.getNodeInfo().Enode
    34  	peerCh := make(chan *p2p.PeerEvent)
    35  	sub, err := g.rpc.Subscribe(context.Background(), "admin", peerCh, "peerEvents")
    36  	if err != nil {
    37  		g.geth.Fatalf("subscribe %v: %v", g.name, err)
    38  	}
    39  	defer sub.Unsubscribe()
    40  	g.callRPC(nil, "admin_addPeer", enode)
    41  	dur := 14 * time.Second
    42  	timeout := time.After(dur)
    43  	select {
    44  	case ev := <-peerCh:
    45  		g.geth.Logf("%v received event: type=%v, peer=%v", g.name, ev.Type, ev.Peer)
    46  	case err := <-sub.Err():
    47  		g.geth.Fatalf("%v sub error: %v", g.name, err)
    48  	case <-timeout:
    49  		g.geth.Error("timeout adding peer after", dur)
    50  	}
    51  }
    52  
    53  // Use this function instead of `g.nodeInfo` directly
    54  func (g *gethrpc) getNodeInfo() *p2p.NodeInfo {
    55  	if g.nodeInfo != nil {
    56  		return g.nodeInfo
    57  	}
    58  	g.nodeInfo = &p2p.NodeInfo{}
    59  	g.callRPC(&g.nodeInfo, "admin_nodeInfo")
    60  	return g.nodeInfo
    61  }
    62  
    63  func (g *gethrpc) waitSynced() {
    64  	// Check if it's synced now
    65  	var result interface{}
    66  	g.callRPC(&result, "eth_syncing")
    67  	syncing, ok := result.(bool)
    68  	if ok && !syncing {
    69  		g.geth.Logf("%v already synced", g.name)
    70  		return
    71  	}
    72  
    73  	// Actually wait, subscribe to the event
    74  	ch := make(chan interface{})
    75  	sub, err := g.rpc.Subscribe(context.Background(), "eth", ch, "syncing")
    76  	if err != nil {
    77  		g.geth.Fatalf("%v syncing: %v", g.name, err)
    78  	}
    79  	defer sub.Unsubscribe()
    80  	timeout := time.After(4 * time.Second)
    81  	select {
    82  	case ev := <-ch:
    83  		g.geth.Log("'syncing' event", ev)
    84  		syncing, ok := ev.(bool)
    85  		if ok && !syncing {
    86  			break
    87  		}
    88  		g.geth.Log("Other 'syncing' event", ev)
    89  	case err := <-sub.Err():
    90  		g.geth.Fatalf("%v notification: %v", g.name, err)
    91  		break
    92  	case <-timeout:
    93  		g.geth.Fatalf("%v timeout syncing", g.name)
    94  		break
    95  	}
    96  }
    97  
    98  func startGethWithIpc(t *testing.T, name string, args ...string) *gethrpc {
    99  	g := &gethrpc{name: name}
   100  	args = append([]string{"--networkid=42", "--port=0", "--nousb"}, args...)
   101  	t.Logf("Starting %v with rpc: %v", name, args)
   102  	g.geth = runGeth(t, args...)
   103  	// wait before we can attach to it. TODO: probe for it properly
   104  	time.Sleep(1 * time.Second)
   105  	var err error
   106  	ipcpath := filepath.Join(g.geth.Datadir, "geth.ipc")
   107  	g.rpc, err = rpc.Dial(ipcpath)
   108  	if err != nil {
   109  		t.Fatalf("%v rpc connect: %v", name, err)
   110  	}
   111  	return g
   112  }
   113  
   114  func initGeth(t *testing.T) string {
   115  	g := runGeth(t, "--nousb", "--networkid=42", "init", "./testdata/clique.json")
   116  	datadir := g.Datadir
   117  	g.WaitExit()
   118  	return datadir
   119  }
   120  
   121  func startLightServer(t *testing.T) *gethrpc {
   122  	datadir := initGeth(t)
   123  	runGeth(t, "--nousb", "--datadir", datadir, "--password", "./testdata/password.txt", "account", "import", "./testdata/key.prv").WaitExit()
   124  	account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105"
   125  	server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1")
   126  	return server
   127  }
   128  
   129  func startClient(t *testing.T, name string) *gethrpc {
   130  	datadir := initGeth(t)
   131  	return startGethWithIpc(t, name, "--datadir", datadir, "--nodiscover", "--syncmode=light", "--nat=extip:127.0.0.1")
   132  }
   133  
   134  func TestPriorityClient(t *testing.T) {
   135  	lightServer := startLightServer(t)
   136  	defer lightServer.killAndWait()
   137  
   138  	// Start client and add lightServer as peer
   139  	freeCli := startClient(t, "freeCli")
   140  	defer freeCli.killAndWait()
   141  	freeCli.addPeer(lightServer)
   142  
   143  	var peers []*p2p.PeerInfo
   144  	freeCli.callRPC(&peers, "admin_peers")
   145  	if len(peers) != 1 {
   146  		t.Errorf("Expected: # of client peers == 1, actual: %v", len(peers))
   147  		return
   148  	}
   149  
   150  	// Set up priority client, get its nodeID, increase its balance on the lightServer
   151  	prioCli := startClient(t, "prioCli")
   152  	defer prioCli.killAndWait()
   153  	// 3_000_000_000 once we move to Go 1.13
   154  	tokens := 3000000000
   155  	lightServer.callRPC(nil, "les_addBalance", prioCli.getNodeInfo().ID, tokens)
   156  	prioCli.addPeer(lightServer)
   157  
   158  	// Check if priority client is actually syncing and the regular client got kicked out
   159  	prioCli.callRPC(&peers, "admin_peers")
   160  	if len(peers) != 1 {
   161  		t.Errorf("Expected: # of prio peers == 1, actual: %v", len(peers))
   162  	}
   163  
   164  	nodes := map[string]*gethrpc{
   165  		lightServer.getNodeInfo().ID: lightServer,
   166  		freeCli.getNodeInfo().ID:     freeCli,
   167  		prioCli.getNodeInfo().ID:     prioCli,
   168  	}
   169  	time.Sleep(1 * time.Second)
   170  	lightServer.callRPC(&peers, "admin_peers")
   171  	peersWithNames := make(map[string]string)
   172  	for _, p := range peers {
   173  		peersWithNames[nodes[p.ID].name] = p.ID
   174  	}
   175  	if _, freeClientFound := peersWithNames[freeCli.name]; freeClientFound {
   176  		t.Error("client is still a peer of lightServer", peersWithNames)
   177  	}
   178  	if _, prioClientFound := peersWithNames[prioCli.name]; !prioClientFound {
   179  		t.Error("prio client is not among lightServer peers", peersWithNames)
   180  	}
   181  }