mirror of https://github.com/ethereum/go-ethereum
cmd/geth: LES priority client test (#20719)
This adds a regression test for the LES priority client API.pull/21283/head
parent
d671dbd5b7
commit
ec51cbb5fb
@ -0,0 +1,180 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"path/filepath" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/p2p" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
) |
||||
|
||||
type gethrpc struct { |
||||
name string |
||||
rpc *rpc.Client |
||||
geth *testgeth |
||||
nodeInfo *p2p.NodeInfo |
||||
} |
||||
|
||||
func (g *gethrpc) killAndWait() { |
||||
g.geth.Kill() |
||||
g.geth.WaitExit() |
||||
} |
||||
|
||||
func (g *gethrpc) callRPC(result interface{}, method string, args ...interface{}) { |
||||
if err := g.rpc.Call(&result, method, args...); err != nil { |
||||
g.geth.Fatalf("callRPC %v: %v", method, err) |
||||
} |
||||
} |
||||
|
||||
func (g *gethrpc) addPeer(peer *gethrpc) { |
||||
g.geth.Logf("%v.addPeer(%v)", g.name, peer.name) |
||||
enode := peer.getNodeInfo().Enode |
||||
peerCh := make(chan *p2p.PeerEvent) |
||||
sub, err := g.rpc.Subscribe(context.Background(), "admin", peerCh, "peerEvents") |
||||
if err != nil { |
||||
g.geth.Fatalf("subscribe %v: %v", g.name, err) |
||||
} |
||||
defer sub.Unsubscribe() |
||||
g.callRPC(nil, "admin_addPeer", enode) |
||||
dur := 14 * time.Second |
||||
timeout := time.After(dur) |
||||
select { |
||||
case ev := <-peerCh: |
||||
g.geth.Logf("%v received event: type=%v, peer=%v", g.name, ev.Type, ev.Peer) |
||||
case err := <-sub.Err(): |
||||
g.geth.Fatalf("%v sub error: %v", g.name, err) |
||||
case <-timeout: |
||||
g.geth.Error("timeout adding peer after", dur) |
||||
} |
||||
} |
||||
|
||||
// Use this function instead of `g.nodeInfo` directly
|
||||
func (g *gethrpc) getNodeInfo() *p2p.NodeInfo { |
||||
if g.nodeInfo != nil { |
||||
return g.nodeInfo |
||||
} |
||||
g.nodeInfo = &p2p.NodeInfo{} |
||||
g.callRPC(&g.nodeInfo, "admin_nodeInfo") |
||||
return g.nodeInfo |
||||
} |
||||
|
||||
func (g *gethrpc) waitSynced() { |
||||
// Check if it's synced now
|
||||
var result interface{} |
||||
g.callRPC(&result, "eth_syncing") |
||||
syncing, ok := result.(bool) |
||||
if ok && !syncing { |
||||
g.geth.Logf("%v already synced", g.name) |
||||
return |
||||
} |
||||
|
||||
// Actually wait, subscribe to the event
|
||||
ch := make(chan interface{}) |
||||
sub, err := g.rpc.Subscribe(context.Background(), "eth", ch, "syncing") |
||||
if err != nil { |
||||
g.geth.Fatalf("%v syncing: %v", g.name, err) |
||||
} |
||||
defer sub.Unsubscribe() |
||||
timeout := time.After(4 * time.Second) |
||||
select { |
||||
case ev := <-ch: |
||||
g.geth.Log("'syncing' event", ev) |
||||
syncing, ok := ev.(bool) |
||||
if ok && !syncing { |
||||
break |
||||
} |
||||
g.geth.Log("Other 'syncing' event", ev) |
||||
case err := <-sub.Err(): |
||||
g.geth.Fatalf("%v notification: %v", g.name, err) |
||||
break |
||||
case <-timeout: |
||||
g.geth.Fatalf("%v timeout syncing", g.name) |
||||
break |
||||
} |
||||
} |
||||
|
||||
func startGethWithRpc(t *testing.T, name string, args ...string) *gethrpc { |
||||
g := &gethrpc{name: name} |
||||
args = append([]string{"--networkid=42", "--port=0", "--nousb", "--rpc", "--rpcport=0", "--rpcapi=admin,eth,les"}, args...) |
||||
t.Logf("Starting %v with rpc: %v", name, args) |
||||
g.geth = runGeth(t, args...) |
||||
// wait before we can attach to it. TODO: probe for it properly
|
||||
time.Sleep(1 * time.Second) |
||||
var err error |
||||
ipcpath := filepath.Join(g.geth.Datadir, "geth.ipc") |
||||
g.rpc, err = rpc.Dial(ipcpath) |
||||
if err != nil { |
||||
t.Fatalf("%v rpc connect: %v", name, err) |
||||
} |
||||
return g |
||||
} |
||||
|
||||
func initGeth(t *testing.T) string { |
||||
g := runGeth(t, "--networkid=42", "init", "./testdata/clique.json") |
||||
datadir := g.Datadir |
||||
g.WaitExit() |
||||
return datadir |
||||
} |
||||
|
||||
func startLightServer(t *testing.T) *gethrpc { |
||||
datadir := initGeth(t) |
||||
runGeth(t, "--datadir", datadir, "--password", "./testdata/password.txt", "account", "import", "./testdata/key.prv").WaitExit() |
||||
account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105" |
||||
server := startGethWithRpc(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") |
||||
return server |
||||
} |
||||
|
||||
func startClient(t *testing.T, name string) *gethrpc { |
||||
datadir := initGeth(t) |
||||
return startGethWithRpc(t, name, "--datadir", datadir, "--nodiscover", "--syncmode=light", "--nat=extip:127.0.0.1") |
||||
} |
||||
|
||||
func TestPriorityClient(t *testing.T) { |
||||
lightServer := startLightServer(t) |
||||
defer lightServer.killAndWait() |
||||
|
||||
// Start client and add lightServer as peer
|
||||
freeCli := startClient(t, "freeCli") |
||||
defer freeCli.killAndWait() |
||||
freeCli.addPeer(lightServer) |
||||
|
||||
var peers []*p2p.PeerInfo |
||||
freeCli.callRPC(&peers, "admin_peers") |
||||
if len(peers) != 1 { |
||||
t.Errorf("Expected: # of client peers == 1, actual: %v", len(peers)) |
||||
return |
||||
} |
||||
|
||||
// Set up priority client, get its nodeID, increase its balance on the lightServer
|
||||
prioCli := startClient(t, "prioCli") |
||||
defer prioCli.killAndWait() |
||||
// 3_000_000_000 once we move to Go 1.13
|
||||
tokens := 3000000000 |
||||
lightServer.callRPC(nil, "les_addBalance", prioCli.getNodeInfo().ID, tokens, "foobar") |
||||
prioCli.addPeer(lightServer) |
||||
|
||||
// Check if priority client is actually syncing and the regular client got kicked out
|
||||
prioCli.callRPC(&peers, "admin_peers") |
||||
if len(peers) != 1 { |
||||
t.Errorf("Expected: # of prio peers == 1, actual: %v", len(peers)) |
||||
} |
||||
|
||||
nodes := map[string]*gethrpc{ |
||||
lightServer.getNodeInfo().ID: lightServer, |
||||
freeCli.getNodeInfo().ID: freeCli, |
||||
prioCli.getNodeInfo().ID: prioCli, |
||||
} |
||||
lightServer.callRPC(&peers, "admin_peers") |
||||
peersWithNames := make(map[string]string) |
||||
for _, p := range peers { |
||||
peersWithNames[nodes[p.ID].name] = p.ID |
||||
} |
||||
if _, freeClientFound := peersWithNames[freeCli.name]; freeClientFound { |
||||
t.Error("client is still a peer of lightServer", peersWithNames) |
||||
} |
||||
if _, prioClientFound := peersWithNames[prioCli.name]; !prioClientFound { |
||||
t.Error("prio client is not among lightServer peers", peersWithNames) |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,24 @@ |
||||
{ |
||||
"config": { |
||||
"chainId": 15, |
||||
"homesteadBlock": 0, |
||||
"eip150Block": 0, |
||||
"eip155Block": 0, |
||||
"eip158Block": 0, |
||||
"byzantiumBlock": 0, |
||||
"constantinopleBlock": 0, |
||||
"petersburgBlock": 0, |
||||
"clique": { |
||||
"period": 5, |
||||
"epoch": 30000 |
||||
} |
||||
}, |
||||
"difficulty": "1", |
||||
"gasLimit": "8000000", |
||||
"extradata": "0x000000000000000000000000000000000000000000000000000000000000000002f0d131f1f97aef08aec6e3291b957d9efe71050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||
"alloc": { |
||||
"02f0d131f1f97aef08aec6e3291b957d9efe7105": { |
||||
"balance": "300000" |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
48aa455c373ec5ce7fefb0e54f44a215decdc85b9047bc4d09801e038909bdbe |
@ -0,0 +1 @@ |
||||
foobar |
Loading…
Reference in new issue