api_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // Copyright 2019 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. package les
  17. import (
  18. "context"
  19. "errors"
  20. "flag"
  21. "io/ioutil"
  22. "math/rand"
  23. "os"
  24. "sync"
  25. "sync/atomic"
  26. "testing"
  27. "time"
  28. "github.com/ethereum/go-ethereum/common"
  29. "github.com/ethereum/go-ethereum/common/hexutil"
  30. "github.com/ethereum/go-ethereum/consensus/ethash"
  31. "github.com/ethereum/go-ethereum/eth"
  32. "github.com/ethereum/go-ethereum/eth/downloader"
  33. "github.com/ethereum/go-ethereum/les/flowcontrol"
  34. "github.com/ethereum/go-ethereum/log"
  35. "github.com/ethereum/go-ethereum/node"
  36. "github.com/ethereum/go-ethereum/p2p/enode"
  37. "github.com/ethereum/go-ethereum/p2p/simulations"
  38. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  39. "github.com/ethereum/go-ethereum/rpc"
  40. "github.com/mattn/go-colorable"
  41. )
  42. /*
  43. This test is not meant to be a part of the automatic testing process because it
  44. runs for a long time and also requires a large database in order to do a meaningful
  45. request performance test. When testServerDataDir is empty, the test is skipped.
  46. */
  47. const (
  48. testServerDataDir = "" // should always be empty on the master branch
  49. testServerCapacity = 200
  50. testMaxClients = 10
  51. testTolerance = 0.1
  52. minRelCap = 0.2
  53. )
  54. func TestCapacityAPI3(t *testing.T) {
  55. testCapacityAPI(t, 3)
  56. }
  57. func TestCapacityAPI6(t *testing.T) {
  58. testCapacityAPI(t, 6)
  59. }
  60. func TestCapacityAPI10(t *testing.T) {
  61. testCapacityAPI(t, 10)
  62. }
  63. // testCapacityAPI runs an end-to-end simulation test connecting one server with
  64. // a given number of clients. It sets different priority capacities to all clients
  65. // except a randomly selected one which runs in free client mode. All clients send
  66. // similar requests at the maximum allowed rate and the test verifies whether the
  67. // ratio of processed requests is close enough to the ratio of assigned capacities.
  68. // Running multiple rounds with different settings ensures that changing capacity
  69. // while connected and going back and forth between free and priority mode with
  70. // the supplied API calls is also thoroughly tested.
  71. func testCapacityAPI(t *testing.T, clientCount int) {
  72. if testServerDataDir == "" {
  73. // Skip test if no data dir specified
  74. return
  75. }
  76. for !testSim(t, 1, clientCount, []string{testServerDataDir}, nil, func(ctx context.Context, net *simulations.Network, servers []*simulations.Node, clients []*simulations.Node) bool {
  77. if len(servers) != 1 {
  78. t.Fatalf("Invalid number of servers: %d", len(servers))
  79. }
  80. server := servers[0]
  81. clientRpcClients := make([]*rpc.Client, len(clients))
  82. serverRpcClient, err := server.Client()
  83. if err != nil {
  84. t.Fatalf("Failed to obtain rpc client: %v", err)
  85. }
  86. headNum, headHash := getHead(ctx, t, serverRpcClient)
  87. totalCap := getTotalCap(ctx, t, serverRpcClient)
  88. minCap := getMinCap(ctx, t, serverRpcClient)
  89. testCap := totalCap * 3 / 4
  90. t.Logf("Server testCap: %d minCap: %d head number: %d head hash: %064x\n", testCap, minCap, headNum, headHash)
  91. reqMinCap := uint64(float64(testCap) * minRelCap / (minRelCap + float64(len(clients)-1)))
  92. if minCap > reqMinCap {
  93. t.Fatalf("Minimum client capacity (%d) bigger than required minimum for this test (%d)", minCap, reqMinCap)
  94. }
  95. freeIdx := rand.Intn(len(clients))
  96. freeCap := getFreeCap(ctx, t, serverRpcClient)
  97. for i, client := range clients {
  98. var err error
  99. clientRpcClients[i], err = client.Client()
  100. if err != nil {
  101. t.Fatalf("Failed to obtain rpc client: %v", err)
  102. }
  103. t.Log("connecting client", i)
  104. if i != freeIdx {
  105. setCapacity(ctx, t, serverRpcClient, client.ID(), testCap/uint64(len(clients)))
  106. }
  107. net.Connect(client.ID(), server.ID())
  108. for {
  109. select {
  110. case <-ctx.Done():
  111. t.Fatalf("Timeout")
  112. default:
  113. }
  114. num, hash := getHead(ctx, t, clientRpcClients[i])
  115. if num == headNum && hash == headHash {
  116. t.Log("client", i, "synced")
  117. break
  118. }
  119. time.Sleep(time.Millisecond * 200)
  120. }
  121. }
  122. var wg sync.WaitGroup
  123. stop := make(chan struct{})
  124. reqCount := make([]uint64, len(clientRpcClients))
  125. for i, c := range clientRpcClients {
  126. wg.Add(1)
  127. i, c := i, c
  128. go func() {
  129. queue := make(chan struct{}, 100)
  130. var count uint64
  131. for {
  132. select {
  133. case queue <- struct{}{}:
  134. select {
  135. case <-stop:
  136. wg.Done()
  137. return
  138. case <-ctx.Done():
  139. wg.Done()
  140. return
  141. default:
  142. wg.Add(1)
  143. go func() {
  144. ok := testRequest(ctx, t, c)
  145. wg.Done()
  146. <-queue
  147. if ok {
  148. count++
  149. atomic.StoreUint64(&reqCount[i], count)
  150. }
  151. }()
  152. }
  153. case <-stop:
  154. wg.Done()
  155. return
  156. case <-ctx.Done():
  157. wg.Done()
  158. return
  159. }
  160. }
  161. }()
  162. }
  163. processedSince := func(start []uint64) []uint64 {
  164. res := make([]uint64, len(reqCount))
  165. for i := range reqCount {
  166. res[i] = atomic.LoadUint64(&reqCount[i])
  167. if start != nil {
  168. res[i] -= start[i]
  169. }
  170. }
  171. return res
  172. }
  173. weights := make([]float64, len(clients))
  174. for c := 0; c < 5; c++ {
  175. setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), freeCap)
  176. freeIdx = rand.Intn(len(clients))
  177. var sum float64
  178. for i := range clients {
  179. if i == freeIdx {
  180. weights[i] = 0
  181. } else {
  182. weights[i] = rand.Float64()*(1-minRelCap) + minRelCap
  183. }
  184. sum += weights[i]
  185. }
  186. for i, client := range clients {
  187. weights[i] *= float64(testCap-freeCap-100) / sum
  188. capacity := uint64(weights[i])
  189. if i != freeIdx && capacity < getCapacity(ctx, t, serverRpcClient, client.ID()) {
  190. setCapacity(ctx, t, serverRpcClient, client.ID(), capacity)
  191. }
  192. }
  193. setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), 0)
  194. for i, client := range clients {
  195. capacity := uint64(weights[i])
  196. if i != freeIdx && capacity > getCapacity(ctx, t, serverRpcClient, client.ID()) {
  197. setCapacity(ctx, t, serverRpcClient, client.ID(), capacity)
  198. }
  199. }
  200. weights[freeIdx] = float64(freeCap)
  201. for i := range clients {
  202. weights[i] /= float64(testCap)
  203. }
  204. time.Sleep(flowcontrol.DecParamDelay)
  205. t.Log("Starting measurement")
  206. t.Logf("Relative weights:")
  207. for i := range clients {
  208. t.Logf(" %f", weights[i])
  209. }
  210. t.Log()
  211. start := processedSince(nil)
  212. for {
  213. select {
  214. case <-ctx.Done():
  215. t.Fatalf("Timeout")
  216. default:
  217. }
  218. totalCap = getTotalCap(ctx, t, serverRpcClient)
  219. if totalCap < testCap {
  220. t.Log("Total capacity underrun")
  221. close(stop)
  222. wg.Wait()
  223. return false
  224. }
  225. processed := processedSince(start)
  226. var avg uint64
  227. t.Logf("Processed")
  228. for i, p := range processed {
  229. t.Logf(" %d", p)
  230. processed[i] = uint64(float64(p) / weights[i])
  231. avg += processed[i]
  232. }
  233. avg /= uint64(len(processed))
  234. if avg >= 10000 {
  235. var maxDev float64
  236. for _, p := range processed {
  237. dev := float64(int64(p-avg)) / float64(avg)
  238. t.Logf(" %7.4f", dev)
  239. if dev < 0 {
  240. dev = -dev
  241. }
  242. if dev > maxDev {
  243. maxDev = dev
  244. }
  245. }
  246. t.Logf(" max deviation: %f totalCap: %d\n", maxDev, totalCap)
  247. if maxDev <= testTolerance {
  248. t.Log("success")
  249. break
  250. }
  251. } else {
  252. t.Log()
  253. }
  254. time.Sleep(time.Millisecond * 200)
  255. }
  256. }
  257. close(stop)
  258. wg.Wait()
  259. for i, count := range reqCount {
  260. t.Log("client", i, "processed", count)
  261. }
  262. return true
  263. }) {
  264. t.Log("restarting test")
  265. }
  266. }
  267. func getHead(ctx context.Context, t *testing.T, client *rpc.Client) (uint64, common.Hash) {
  268. res := make(map[string]interface{})
  269. if err := client.CallContext(ctx, &res, "eth_getBlockByNumber", "latest", false); err != nil {
  270. t.Fatalf("Failed to obtain head block: %v", err)
  271. }
  272. numStr, ok := res["number"].(string)
  273. if !ok {
  274. t.Fatalf("RPC block number field invalid")
  275. }
  276. num, err := hexutil.DecodeUint64(numStr)
  277. if err != nil {
  278. t.Fatalf("Failed to decode RPC block number: %v", err)
  279. }
  280. hashStr, ok := res["hash"].(string)
  281. if !ok {
  282. t.Fatalf("RPC block number field invalid")
  283. }
  284. hash := common.HexToHash(hashStr)
  285. return num, hash
  286. }
  287. func testRequest(ctx context.Context, t *testing.T, client *rpc.Client) bool {
  288. //res := make(map[string]interface{})
  289. var res string
  290. var addr common.Address
  291. rand.Read(addr[:])
  292. c, _ := context.WithTimeout(ctx, time.Second*12)
  293. // if err := client.CallContext(ctx, &res, "eth_getProof", addr, nil, "latest"); err != nil {
  294. err := client.CallContext(c, &res, "eth_getBalance", addr, "latest")
  295. if err != nil {
  296. t.Log("request error:", err)
  297. }
  298. return err == nil
  299. }
  300. func setCapacity(ctx context.Context, t *testing.T, server *rpc.Client, clientID enode.ID, cap uint64) {
  301. if err := server.CallContext(ctx, nil, "les_setClientCapacity", clientID, cap); err != nil {
  302. t.Fatalf("Failed to set client capacity: %v", err)
  303. }
  304. }
  305. func getCapacity(ctx context.Context, t *testing.T, server *rpc.Client, clientID enode.ID) uint64 {
  306. var s string
  307. if err := server.CallContext(ctx, &s, "les_getClientCapacity", clientID); err != nil {
  308. t.Fatalf("Failed to get client capacity: %v", err)
  309. }
  310. cap, err := hexutil.DecodeUint64(s)
  311. if err != nil {
  312. t.Fatalf("Failed to decode client capacity: %v", err)
  313. }
  314. return cap
  315. }
  316. func getTotalCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 {
  317. var s string
  318. if err := server.CallContext(ctx, &s, "les_totalCapacity"); err != nil {
  319. t.Fatalf("Failed to query total capacity: %v", err)
  320. }
  321. total, err := hexutil.DecodeUint64(s)
  322. if err != nil {
  323. t.Fatalf("Failed to decode total capacity: %v", err)
  324. }
  325. return total
  326. }
  327. func getMinCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 {
  328. var s string
  329. if err := server.CallContext(ctx, &s, "les_minimumCapacity"); err != nil {
  330. t.Fatalf("Failed to query minimum capacity: %v", err)
  331. }
  332. min, err := hexutil.DecodeUint64(s)
  333. if err != nil {
  334. t.Fatalf("Failed to decode minimum capacity: %v", err)
  335. }
  336. return min
  337. }
  338. func getFreeCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 {
  339. var s string
  340. if err := server.CallContext(ctx, &s, "les_freeClientCapacity"); err != nil {
  341. t.Fatalf("Failed to query free client capacity: %v", err)
  342. }
  343. free, err := hexutil.DecodeUint64(s)
  344. if err != nil {
  345. t.Fatalf("Failed to decode free client capacity: %v", err)
  346. }
  347. return free
  348. }
  349. func init() {
  350. flag.Parse()
  351. // register the Delivery service which will run as a devp2p
  352. // protocol when using the exec adapter
  353. adapters.RegisterServices(services)
  354. log.PrintOrigins(true)
  355. log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
  356. }
  357. var (
  358. adapter = flag.String("adapter", "exec", "type of simulation: sim|socket|exec|docker")
  359. loglevel = flag.Int("loglevel", 0, "verbosity of logs")
  360. nodes = flag.Int("nodes", 0, "number of nodes")
  361. )
  362. var services = adapters.Services{
  363. "lesclient": newLesClientService,
  364. "lesserver": newLesServerService,
  365. }
  366. func NewNetwork() (*simulations.Network, func(), error) {
  367. adapter, adapterTeardown, err := NewAdapter(*adapter, services)
  368. if err != nil {
  369. return nil, adapterTeardown, err
  370. }
  371. defaultService := "streamer"
  372. net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
  373. ID: "0",
  374. DefaultService: defaultService,
  375. })
  376. teardown := func() {
  377. adapterTeardown()
  378. net.Shutdown()
  379. }
  380. return net, teardown, nil
  381. }
  382. func NewAdapter(adapterType string, services adapters.Services) (adapter adapters.NodeAdapter, teardown func(), err error) {
  383. teardown = func() {}
  384. switch adapterType {
  385. case "sim":
  386. adapter = adapters.NewSimAdapter(services)
  387. // case "socket":
  388. // adapter = adapters.NewSocketAdapter(services)
  389. case "exec":
  390. baseDir, err0 := ioutil.TempDir("", "les-test")
  391. if err0 != nil {
  392. return nil, teardown, err0
  393. }
  394. teardown = func() { os.RemoveAll(baseDir) }
  395. adapter = adapters.NewExecAdapter(baseDir)
  396. /*case "docker":
  397. adapter, err = adapters.NewDockerAdapter()
  398. if err != nil {
  399. return nil, teardown, err
  400. }*/
  401. default:
  402. return nil, teardown, errors.New("adapter needs to be one of sim, socket, exec, docker")
  403. }
  404. return adapter, teardown, nil
  405. }
  406. func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []string, test func(ctx context.Context, net *simulations.Network, servers []*simulations.Node, clients []*simulations.Node) bool) bool {
  407. net, teardown, err := NewNetwork()
  408. defer teardown()
  409. if err != nil {
  410. t.Fatalf("Failed to create network: %v", err)
  411. }
  412. timeout := 1800 * time.Second
  413. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  414. defer cancel()
  415. servers := make([]*simulations.Node, serverCount)
  416. clients := make([]*simulations.Node, clientCount)
  417. for i := range clients {
  418. clientconf := adapters.RandomNodeConfig()
  419. clientconf.Services = []string{"lesclient"}
  420. if len(clientDir) == clientCount {
  421. clientconf.DataDir = clientDir[i]
  422. }
  423. client, err := net.NewNodeWithConfig(clientconf)
  424. if err != nil {
  425. t.Fatalf("Failed to create client: %v", err)
  426. }
  427. clients[i] = client
  428. }
  429. for i := range servers {
  430. serverconf := adapters.RandomNodeConfig()
  431. serverconf.Services = []string{"lesserver"}
  432. if len(serverDir) == serverCount {
  433. serverconf.DataDir = serverDir[i]
  434. }
  435. server, err := net.NewNodeWithConfig(serverconf)
  436. if err != nil {
  437. t.Fatalf("Failed to create server: %v", err)
  438. }
  439. servers[i] = server
  440. }
  441. for _, client := range clients {
  442. if err := net.Start(client.ID()); err != nil {
  443. t.Fatalf("Failed to start client node: %v", err)
  444. }
  445. }
  446. for _, server := range servers {
  447. if err := net.Start(server.ID()); err != nil {
  448. t.Fatalf("Failed to start server node: %v", err)
  449. }
  450. }
  451. return test(ctx, net, servers, clients)
  452. }
  453. func newLesClientService(ctx *adapters.ServiceContext) (node.Service, error) {
  454. config := eth.DefaultConfig
  455. config.SyncMode = downloader.LightSync
  456. config.Ethash.PowMode = ethash.ModeFake
  457. return New(ctx.NodeContext, &config)
  458. }
  459. func newLesServerService(ctx *adapters.ServiceContext) (node.Service, error) {
  460. config := eth.DefaultConfig
  461. config.SyncMode = downloader.FullSync
  462. config.LightServ = testServerCapacity
  463. config.LightPeers = testMaxClients
  464. ethereum, err := eth.New(ctx.NodeContext, &config)
  465. if err != nil {
  466. return nil, err
  467. }
  468. server, err := NewLesServer(ethereum, &config)
  469. if err != nil {
  470. return nil, err
  471. }
  472. ethereum.AddLesServer(server)
  473. return ethereum, nil
  474. }