diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go new file mode 100644 index 0000000000..f7a484cf63 --- /dev/null +++ b/cmd/geth/les_test.go @@ -0,0 +1,247 @@ +package main + +import ( + "os" + "path/filepath" + "testing" + "time" + + "github.com/ethereum/go-ethereum/rpc" +) + +/* +var rpcArgs = []string{"--rpc", "--rpcapi=admin,eth,les"} + +var port int = 30303 +var rpcPort int = 8545 + +type gethNode struct { + datadir string + args []string + cmd *exec.Cmd + rpc *rpc.Client +} + +func startGeth(datadir string, keepDatadir bool, args ...string) (*gethNode, error) { + g := &gethNode{datadir, args, nil, nil} + if !keepDatadir { + err := os.RemoveAll(datadir) + if err != nil { + return g, err + } + } + allArgs := []string{"--datadir", datadir, "--port", fmt.Sprintf("%d", port), "--rpcport", fmt.Sprintf("%d", rpcPort)} + port += 1 + rpcPort += 1 + allArgs = append(allArgs, rpcArgs...) + allArgs = append(allArgs, args...) + cmd := exec.Command("geth", allArgs...) + log.Println("to start", cmd.String()) + var err error + cmd.Stderr = os.Stderr + err = cmd.Start() + if err != nil { + return nil, err + } + g.cmd = cmd + time.Sleep(1 * time.Second) // wait before we can attach to it + // TODO: probe for it properly + g.rpc, err = rpc.Dial(g.ipcpath()) + if err != nil { + return nil, err + } + return g, nil +} + + +// Start and wait for it to finish +func runGeth(datadir string, keepDatadir bool, args ...string) error { + if !keepDatadir { + if err := os.RemoveAll(datadir); err != nil { + return err + } + } + allArgs := []string{"--datadir", datadir} + allArgs = append(allArgs, args...) + cmd := exec.Command("geth", allArgs...) + log.Println("to run", cmd.String()) + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + return fmt.Errorf("starting but %s", err) + } + if err := cmd.Wait(); err != nil { + return fmt.Errorf("waiting but %s", err) + } + return nil +} + +func (g *gethNode) ipcpath() string { + return filepath.Join(g.datadir, "geth.ipc") +} + +func (g *gethNode) kill() error { + err := g.cmd.Process.Kill() + if err != nil { + return err + } + _, err = g.cmd.Process.Wait() + return err +} + +func (g *gethNode) addPeer(enode string) error { + peerCh := make(chan *p2p.PeerEvent) + sub, err := g.rpc.Subscribe(context.Background(), "admin", peerCh, "peerEvents") + if err != nil { + return fmt.Errorf("subscribe: %v", err) + } + defer sub.Unsubscribe() + if err := g.rpc.Call(nil, "admin_addPeer", enode); err != nil { + return fmt.Errorf("admin_addPeer: %v", err) + } + select { + case ev := <-peerCh: + fmt.Print("event", ev) + + case err := <-sub.Err(): + return fmt.Errorf("notification: %v", err) + } + return nil +} + +func (g *gethNode) waitSynced() error { + ch := make(chan interface{}) + sub, err := g.rpc.Subscribe(context.Background(), "eth", ch, "syncing") + if err != nil { + return fmt.Errorf("syncing: %v", err) + } + defer sub.Unsubscribe() + timeout := time.After(40 * time.Second) + for { + select { + case ev := <-ch: + syncing, ok := ev.(bool) + if ok && !syncing { + return nil + } + case err := <-sub.Err(): + return fmt.Errorf("notification: %v", err) + case <-timeout: + return fmt.Errorf("timeout syncing") + } + } +} +*/ + +func startLightServer(t *testing.T) *rpc.Client { + // Create a temporary data directory to use + datadir := tmpdir(t) + defer os.RemoveAll(datadir) + ipcpath := filepath.Join(datadir, "geth.ipc") + + t.Log("server datadir", datadir) + runGeth(t, "--datadir", datadir, "init", "./testdata/genesis.json").WaitExit() + t.Log("init done") + runGeth(t, "--datadir", datadir, "--gcmode=archive", "import", "./testdata/blockchain.blocks").WaitExit() + t.Log("import done") + geth := runGeth(t, "--datadir", datadir, "--networkid=42", "--port=0", "--rpcport=0", "--rpc", "--rpcapi=admin,eth,les", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1") + defer geth.WaitExit() + defer geth.Kill() + t.Log("started lightserver") + + // wait before we can attach to it. TODO: probe for it properly + time.Sleep(1 * time.Second) + rpc, err := rpc.Dial(ipcpath) + if err != nil { + t.Fatalf("rpc connect: %v", err) + } + return rpc +} + +func TestPriorityClient(t *testing.T) { + // Init and start server + server := startLightServer(t) + nodeInfo := make(map[string]interface{}) + if err := server.Call(&nodeInfo, "admin_nodeInfo"); err != nil { + t.Fatal("nodeInfo:", err) + } + enode := nodeInfo["enode"].(string) + t.Log("enode", enode) + /* + if err := runGeth(datadir, true, "--gcmode=archive", "import", "./initdata/testBlockchain.blocks"); err != nil { + t.Fatal("import", err) + } + t.Log("import done") + server, err := startGeth(datadir, true, "--networkid=42", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1") + defer server.kill() + if err != nil { + t.Fatal("start server", err) + } + nodeInfo := make(map[string]interface{}) + if err := server.rpc.Call(&nodeInfo, "admin_nodeInfo"); err != nil { + t.Fatal("nodeInfo:", err) + } + enode := nodeInfo["enode"].(string) + t.Log("enode", enode) + + // Client + clientdir := "/tmp/client" + if err := runGeth(clientdir, false, "init", "./initdata/testGenesis.json"); err != nil { + t.Fatal("init client", err) + } + client, err := startGeth(clientdir, true, "--networkid=42", "--syncmode=light", "--nodiscover") + defer client.kill() + if err != nil { + t.Fatal("start client", err) + } + if err := client.addPeer(enode); err != nil { + t.Fatal("addPeer", err) + } + var peers []interface{} + if err := client.rpc.Call(&peers, "admin_peers"); err != nil { + t.Fatal("peers", err) + } + if len(peers) != 1 { + t.Log("Expected: # of client peers == 1") + t.Fail() + } + + // Priority client + priodir := "/tmp/prio" + if err := runGeth(priodir, false, "init", "./initdata/testGenesis.json"); err != nil { + t.Fatal("init prio", err) + } + prio, err := startGeth(priodir, true, "--networkid=42", "--syncmode=light", "--nodiscover") + defer prio.kill() + if err != nil { + t.Fatal(prio.cmd.String(), err) + } + prioNodeInfo := make(map[string]interface{}) + if err := prio.rpc.Call(&prioNodeInfo, "admin_nodeInfo"); err != nil { + t.Fatal("prio nodeInfo:", err) + } + nodeID := prioNodeInfo["id"].(string) + t.Log("nodeID", nodeID) + tokens := 3_000_000_000 + if err := server.rpc.Call(nil, "les_addBalance", nodeID, tokens, "foobar"); err != nil { + t.Fatal("addBalance:", err) + } + if err := prio.addPeer(enode); err != nil { + t.Fatal("addPeer", err) + } + + // Check if priority client is actually syncing and the regular client got kicked out + if err := prio.rpc.Call(&peers, "admin_peers"); err != nil { + t.Fatal("prio peers", err) + } + if len(peers) != 1 { + t.Fatal("Expected: # of prio peers == 1") + } + + if err := client.rpc.Call(&peers, "admin_peers"); err != nil { + t.Fatal("client peers", err) + } + if len(peers) > 0 { + t.Fatal("Expected: # of client peers == 0") + } + */ +} diff --git a/cmd/geth/testdata/blockchain.blocks b/cmd/geth/testdata/blockchain.blocks new file mode 100644 index 0000000000..d29453d3e5 Binary files /dev/null and b/cmd/geth/testdata/blockchain.blocks differ diff --git a/cmd/geth/testdata/genesis.json b/cmd/geth/testdata/genesis.json new file mode 100644 index 0000000000..e77446ed05 --- /dev/null +++ b/cmd/geth/testdata/genesis.json @@ -0,0 +1,34 @@ +{ + "version": "1", + "params":{ + "petersburgForkBlock":"0x0", + "chainId":"0xdeadbeef", + "miningMethod":"ethash" + }, + "genesis":{ + "author":"0x0000000000000000000000000000000000000000", + "difficulty":"0x1", + "extraData":"0xdeadbeef", + "gasLimit":"0x900000", + "nonce":"0x00000000deadbeef", + "timestamp":"0x0" + }, + "config": { + "chainId": 42, + "ethash": { + } + }, + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "gasLimit" : "0x2fefd8", + "timestamp" : "0x54c98c81", + "extraData" : "0x42", + "mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46", + "nonce" : "0x78cc16f7b4f65485", + "alloc" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance" : "0x09184e72a000" + } + } +} \ No newline at end of file