github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/les/lespay/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  
    24  	"github.com/cryptogateway/go-paymex/common/mclock"
    25  	"github.com/cryptogateway/go-paymex/p2p/enode"
    26  	"github.com/cryptogateway/go-paymex/p2p/enr"
    27  	"github.com/cryptogateway/go-paymex/p2p/nodestate"
    28  )
    29  
    30  var (
    31  	testSetup         = &nodestate.Setup{}
    32  	ppTestClientFlag  = testSetup.NewFlag("ppTestClientFlag")
    33  	ppTestClientField = testSetup.NewField("ppTestClient", reflect.TypeOf(&ppTestClient{}))
    34  	ppUpdateFlag      = testSetup.NewFlag("ppUpdateFlag")
    35  	ppTestSetup       = NewPriorityPoolSetup(testSetup)
    36  )
    37  
    38  func init() {
    39  	ppTestSetup.Connect(ppTestClientField, ppUpdateFlag)
    40  }
    41  
    42  const (
    43  	testCapacityStepDiv      = 100
    44  	testCapacityToleranceDiv = 10
    45  )
    46  
    47  type ppTestClient struct {
    48  	node         *enode.Node
    49  	balance, cap uint64
    50  }
    51  
    52  func (c *ppTestClient) Priority(now mclock.AbsTime, cap uint64) int64 {
    53  	return int64(c.balance / cap)
    54  }
    55  
    56  func (c *ppTestClient) EstMinPriority(until mclock.AbsTime, cap uint64, update bool) int64 {
    57  	return int64(c.balance / cap)
    58  }
    59  
    60  func TestPriorityPool(t *testing.T) {
    61  	clock := &mclock.Simulated{}
    62  	ns := nodestate.NewNodeStateMachine(nil, nil, clock, testSetup)
    63  
    64  	ns.SubscribeField(ppTestSetup.CapacityField, func(node *enode.Node, state nodestate.Flags, oldValue, newValue interface{}) {
    65  		if n := ns.GetField(node, ppTestSetup.priorityField); n != nil {
    66  			c := n.(*ppTestClient)
    67  			c.cap = newValue.(uint64)
    68  		}
    69  	})
    70  	pp := NewPriorityPool(ns, ppTestSetup, clock, 100, 0, testCapacityStepDiv)
    71  	ns.Start()
    72  	pp.SetLimits(100, 1000000)
    73  	clients := make([]*ppTestClient, 100)
    74  	raise := func(c *ppTestClient) {
    75  		for {
    76  			var ok bool
    77  			ns.Operation(func() {
    78  				_, ok = pp.RequestCapacity(c.node, c.cap+c.cap/testCapacityStepDiv, 0, true)
    79  			})
    80  			if !ok {
    81  				return
    82  			}
    83  		}
    84  	}
    85  	var sumBalance uint64
    86  	check := func(c *ppTestClient) {
    87  		expCap := 1000000 * c.balance / sumBalance
    88  		capTol := expCap / testCapacityToleranceDiv
    89  		if c.cap < expCap-capTol || c.cap > expCap+capTol {
    90  			t.Errorf("Wrong node capacity (expected %d, got %d)", expCap, c.cap)
    91  		}
    92  	}
    93  
    94  	for i := range clients {
    95  		c := &ppTestClient{
    96  			node:    enode.SignNull(&enr.Record{}, enode.ID{byte(i)}),
    97  			balance: 1000000000,
    98  			cap:     1000,
    99  		}
   100  		sumBalance += c.balance
   101  		clients[i] = c
   102  		ns.SetState(c.node, ppTestClientFlag, nodestate.Flags{}, 0)
   103  		ns.SetField(c.node, ppTestSetup.priorityField, c)
   104  		ns.SetState(c.node, ppTestSetup.InactiveFlag, nodestate.Flags{}, 0)
   105  		raise(c)
   106  		check(c)
   107  	}
   108  
   109  	for count := 0; count < 100; count++ {
   110  		c := clients[rand.Intn(len(clients))]
   111  		oldBalance := c.balance
   112  		c.balance = uint64(rand.Int63n(1000000000) + 1000000000)
   113  		sumBalance += c.balance - oldBalance
   114  		pp.ns.SetState(c.node, ppUpdateFlag, nodestate.Flags{}, 0)
   115  		pp.ns.SetState(c.node, nodestate.Flags{}, ppUpdateFlag, 0)
   116  		if c.balance > oldBalance {
   117  			raise(c)
   118  		} else {
   119  			for _, c := range clients {
   120  				raise(c)
   121  			}
   122  		}
   123  		for _, c := range clients {
   124  			check(c)
   125  		}
   126  	}
   127  
   128  	ns.Stop()
   129  }