github.com/hardtosaygoodbye/go-ethereum@v1.10.16-0.20220122011429-97003b9e6c15/les/vflux/server/prioritypool_test.go (about)

     1  // Copyright 2020 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 server
    18  
    19  import (
    20  	"math/rand"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/hardtosaygoodbye/go-ethereum/common/mclock"
    26  	"github.com/hardtosaygoodbye/go-ethereum/p2p/enode"
    27  	"github.com/hardtosaygoodbye/go-ethereum/p2p/enr"
    28  	"github.com/hardtosaygoodbye/go-ethereum/p2p/nodestate"
    29  )
    30  
    31  const (
    32  	testCapacityStepDiv      = 100
    33  	testCapacityToleranceDiv = 10
    34  	testMinCap               = 100
    35  )
    36  
    37  type ppTestClient struct {
    38  	node         *enode.Node
    39  	balance, cap uint64
    40  }
    41  
    42  func (c *ppTestClient) priority(cap uint64) int64 {
    43  	return int64(c.balance / cap)
    44  }
    45  
    46  func (c *ppTestClient) estimatePriority(cap uint64, addBalance int64, future, bias time.Duration, update bool) int64 {
    47  	return int64(c.balance / cap)
    48  }
    49  
    50  func TestPriorityPool(t *testing.T) {
    51  	clock := &mclock.Simulated{}
    52  	setup := newServerSetup()
    53  	setup.balanceField = setup.setup.NewField("ppTestClient", reflect.TypeOf(&ppTestClient{}))
    54  	ns := nodestate.NewNodeStateMachine(nil, nil, clock, setup.setup)
    55  
    56  	ns.SubscribeField(setup.capacityField, func(node *enode.Node, state nodestate.Flags, oldValue, newValue interface{}) {
    57  		if n := ns.GetField(node, setup.balanceField); n != nil {
    58  			c := n.(*ppTestClient)
    59  			c.cap = newValue.(uint64)
    60  		}
    61  	})
    62  	pp := newPriorityPool(ns, setup, clock, testMinCap, 0, testCapacityStepDiv, testCapacityStepDiv)
    63  	ns.Start()
    64  	pp.SetLimits(100, 1000000)
    65  	clients := make([]*ppTestClient, 100)
    66  	raise := func(c *ppTestClient) {
    67  		for {
    68  			var ok bool
    69  			ns.Operation(func() {
    70  				newCap := c.cap + c.cap/testCapacityStepDiv
    71  				ok = pp.requestCapacity(c.node, newCap, newCap, 0) == newCap
    72  			})
    73  			if !ok {
    74  				return
    75  			}
    76  		}
    77  	}
    78  	var sumBalance uint64
    79  	check := func(c *ppTestClient) {
    80  		expCap := 1000000 * c.balance / sumBalance
    81  		capTol := expCap / testCapacityToleranceDiv
    82  		if c.cap < expCap-capTol || c.cap > expCap+capTol {
    83  			t.Errorf("Wrong node capacity (expected %d, got %d)", expCap, c.cap)
    84  		}
    85  	}
    86  
    87  	for i := range clients {
    88  		c := &ppTestClient{
    89  			node:    enode.SignNull(&enr.Record{}, enode.ID{byte(i)}),
    90  			balance: 100000000000,
    91  			cap:     1000,
    92  		}
    93  		sumBalance += c.balance
    94  		clients[i] = c
    95  		ns.SetField(c.node, setup.balanceField, c)
    96  		ns.SetState(c.node, setup.inactiveFlag, nodestate.Flags{}, 0)
    97  		raise(c)
    98  		check(c)
    99  	}
   100  
   101  	for count := 0; count < 100; count++ {
   102  		c := clients[rand.Intn(len(clients))]
   103  		oldBalance := c.balance
   104  		c.balance = uint64(rand.Int63n(100000000000) + 100000000000)
   105  		sumBalance += c.balance - oldBalance
   106  		pp.ns.SetState(c.node, setup.updateFlag, nodestate.Flags{}, 0)
   107  		pp.ns.SetState(c.node, nodestate.Flags{}, setup.updateFlag, 0)
   108  		if c.balance > oldBalance {
   109  			raise(c)
   110  		} else {
   111  			for _, c := range clients {
   112  				raise(c)
   113  			}
   114  		}
   115  		// check whether capacities are proportional to balances
   116  		for _, c := range clients {
   117  			check(c)
   118  		}
   119  		if count%10 == 0 {
   120  			// test available capacity calculation with capacity curve
   121  			c = clients[rand.Intn(len(clients))]
   122  			curve := pp.getCapacityCurve().exclude(c.node.ID())
   123  
   124  			add := uint64(rand.Int63n(10000000000000))
   125  			c.balance += add
   126  			sumBalance += add
   127  			expCap := curve.maxCapacity(func(cap uint64) int64 {
   128  				return int64(c.balance / cap)
   129  			})
   130  			var ok bool
   131  			expFail := expCap + 10
   132  			if expFail < testMinCap {
   133  				expFail = testMinCap
   134  			}
   135  			ns.Operation(func() {
   136  				ok = pp.requestCapacity(c.node, expFail, expFail, 0) == expFail
   137  			})
   138  			if ok {
   139  				t.Errorf("Request for more than expected available capacity succeeded")
   140  			}
   141  			if expCap >= testMinCap {
   142  				ns.Operation(func() {
   143  					ok = pp.requestCapacity(c.node, expCap, expCap, 0) == expCap
   144  				})
   145  				if !ok {
   146  					t.Errorf("Request for expected available capacity failed")
   147  				}
   148  			}
   149  			c.balance -= add
   150  			sumBalance -= add
   151  			pp.ns.SetState(c.node, setup.updateFlag, nodestate.Flags{}, 0)
   152  			pp.ns.SetState(c.node, nodestate.Flags{}, setup.updateFlag, 0)
   153  			for _, c := range clients {
   154  				raise(c)
   155  			}
   156  		}
   157  	}
   158  
   159  	ns.Stop()
   160  }
   161  
   162  func TestCapacityCurve(t *testing.T) {
   163  	clock := &mclock.Simulated{}
   164  	setup := newServerSetup()
   165  	setup.balanceField = setup.setup.NewField("ppTestClient", reflect.TypeOf(&ppTestClient{}))
   166  	ns := nodestate.NewNodeStateMachine(nil, nil, clock, setup.setup)
   167  
   168  	pp := newPriorityPool(ns, setup, clock, 400000, 0, 2, 2)
   169  	ns.Start()
   170  	pp.SetLimits(10, 10000000)
   171  	clients := make([]*ppTestClient, 10)
   172  
   173  	for i := range clients {
   174  		c := &ppTestClient{
   175  			node:    enode.SignNull(&enr.Record{}, enode.ID{byte(i)}),
   176  			balance: 100000000000 * uint64(i+1),
   177  			cap:     1000000,
   178  		}
   179  		clients[i] = c
   180  		ns.SetField(c.node, setup.balanceField, c)
   181  		ns.SetState(c.node, setup.inactiveFlag, nodestate.Flags{}, 0)
   182  		ns.Operation(func() {
   183  			pp.requestCapacity(c.node, c.cap, c.cap, 0)
   184  		})
   185  	}
   186  
   187  	curve := pp.getCapacityCurve()
   188  	check := func(balance, expCap uint64) {
   189  		cap := curve.maxCapacity(func(cap uint64) int64 {
   190  			return int64(balance / cap)
   191  		})
   192  		var fail bool
   193  		if cap == 0 || expCap == 0 {
   194  			fail = cap != expCap
   195  		} else {
   196  			pri := balance / cap
   197  			expPri := balance / expCap
   198  			fail = pri != expPri && pri != expPri+1
   199  		}
   200  		if fail {
   201  			t.Errorf("Incorrect capacity for %d balance (got %d, expected %d)", balance, cap, expCap)
   202  		}
   203  	}
   204  
   205  	check(0, 0)
   206  	check(10000000000, 100000)
   207  	check(50000000000, 500000)
   208  	check(100000000000, 1000000)
   209  	check(200000000000, 1000000)
   210  	check(300000000000, 1500000)
   211  	check(450000000000, 1500000)
   212  	check(600000000000, 2000000)
   213  	check(800000000000, 2000000)
   214  	check(1000000000000, 2500000)
   215  
   216  	pp.SetLimits(11, 10000000)
   217  	curve = pp.getCapacityCurve()
   218  
   219  	check(0, 0)
   220  	check(10000000000, 100000)
   221  	check(50000000000, 500000)
   222  	check(150000000000, 750000)
   223  	check(200000000000, 1000000)
   224  	check(220000000000, 1100000)
   225  	check(275000000000, 1100000)
   226  	check(375000000000, 1500000)
   227  	check(450000000000, 1500000)
   228  	check(600000000000, 2000000)
   229  	check(800000000000, 2000000)
   230  	check(1000000000000, 2500000)
   231  
   232  	ns.Stop()
   233  }