github.com/bloxroute-labs/bor@v0.1.4/les/freeclient_test.go (about)

     1  // Copyright 2017 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  
    17  package les
    18  
    19  import (
    20  	"fmt"
    21  	"math/rand"
    22  	"strconv"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/maticnetwork/bor/common/mclock"
    27  	"github.com/maticnetwork/bor/core/rawdb"
    28  )
    29  
    30  func TestFreeClientPoolL10C100(t *testing.T) {
    31  	testFreeClientPool(t, 10, 100)
    32  }
    33  
    34  func TestFreeClientPoolL40C200(t *testing.T) {
    35  	testFreeClientPool(t, 40, 200)
    36  }
    37  
    38  func TestFreeClientPoolL100C300(t *testing.T) {
    39  	testFreeClientPool(t, 100, 300)
    40  }
    41  
    42  const testFreeClientPoolTicks = 500000
    43  
    44  func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
    45  	var (
    46  		clock       mclock.Simulated
    47  		db          = rawdb.NewMemoryDatabase()
    48  		connected   = make([]bool, clientCount)
    49  		connTicks   = make([]int, clientCount)
    50  		disconnCh   = make(chan int, clientCount)
    51  		peerAddress = func(i int) string {
    52  			return fmt.Sprintf("addr #%d", i)
    53  		}
    54  		peerId = func(i int) string {
    55  			return fmt.Sprintf("id #%d", i)
    56  		}
    57  		disconnFn = func(id string) {
    58  			i, err := strconv.Atoi(id[4:])
    59  			if err != nil {
    60  				panic(err)
    61  			}
    62  			disconnCh <- i
    63  		}
    64  		pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn)
    65  	)
    66  	pool.setLimits(connLimit, uint64(connLimit))
    67  
    68  	// pool should accept new peers up to its connected limit
    69  	for i := 0; i < connLimit; i++ {
    70  		if pool.connect(peerAddress(i), peerId(i)) {
    71  			connected[i] = true
    72  		} else {
    73  			t.Fatalf("Test peer #%d rejected", i)
    74  		}
    75  	}
    76  	// since all accepted peers are new and should not be kicked out, the next one should be rejected
    77  	if pool.connect(peerAddress(connLimit), peerId(connLimit)) {
    78  		connected[connLimit] = true
    79  		t.Fatalf("Peer accepted over connected limit")
    80  	}
    81  
    82  	// randomly connect and disconnect peers, expect to have a similar total connection time at the end
    83  	for tickCounter := 0; tickCounter < testFreeClientPoolTicks; tickCounter++ {
    84  		clock.Run(1 * time.Second)
    85  
    86  		i := rand.Intn(clientCount)
    87  		if connected[i] {
    88  			pool.disconnect(peerAddress(i))
    89  			connected[i] = false
    90  			connTicks[i] += tickCounter
    91  		} else {
    92  			if pool.connect(peerAddress(i), peerId(i)) {
    93  				connected[i] = true
    94  				connTicks[i] -= tickCounter
    95  			}
    96  		}
    97  	pollDisconnects:
    98  		for {
    99  			select {
   100  			case i := <-disconnCh:
   101  				pool.disconnect(peerAddress(i))
   102  				if connected[i] {
   103  					connTicks[i] += tickCounter
   104  					connected[i] = false
   105  				}
   106  			default:
   107  				break pollDisconnects
   108  			}
   109  		}
   110  	}
   111  
   112  	expTicks := testFreeClientPoolTicks * connLimit / clientCount
   113  	expMin := expTicks - expTicks/10
   114  	expMax := expTicks + expTicks/10
   115  
   116  	// check if the total connected time of peers are all in the expected range
   117  	for i, c := range connected {
   118  		if c {
   119  			connTicks[i] += testFreeClientPoolTicks
   120  		}
   121  		if connTicks[i] < expMin || connTicks[i] > expMax {
   122  			t.Errorf("Total connected time of test node #%d (%d) outside expected range (%d to %d)", i, connTicks[i], expMin, expMax)
   123  		}
   124  	}
   125  
   126  	// a previously unknown peer should be accepted now
   127  	if !pool.connect("newAddr", "newId") {
   128  		t.Fatalf("Previously unknown peer rejected")
   129  	}
   130  
   131  	// close and restart pool
   132  	pool.stop()
   133  	pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn)
   134  	pool.setLimits(connLimit, uint64(connLimit))
   135  
   136  	// try connecting all known peers (connLimit should be filled up)
   137  	for i := 0; i < clientCount; i++ {
   138  		pool.connect(peerAddress(i), peerId(i))
   139  	}
   140  	// expect pool to remember known nodes and kick out one of them to accept a new one
   141  	if !pool.connect("newAddr2", "newId2") {
   142  		t.Errorf("Previously unknown peer rejected after restarting pool")
   143  	}
   144  	pool.stop()
   145  }