code.vegaprotocol.io/vega@v0.79.0/core/validators/validator_score_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package validators
    17  
    18  import (
    19  	"context"
    20  	"math/rand"
    21  	"testing"
    22  
    23  	bmocks "code.vegaprotocol.io/vega/core/broker/mocks"
    24  	"code.vegaprotocol.io/vega/core/events"
    25  	"code.vegaprotocol.io/vega/core/types"
    26  	"code.vegaprotocol.io/vega/libs/num"
    27  	"code.vegaprotocol.io/vega/logging"
    28  	v1 "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    29  
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/stretchr/testify/require"
    32  	"golang.org/x/exp/maps"
    33  )
    34  
    35  type TestMultisigTopology struct {
    36  	validators map[string]struct{}
    37  }
    38  
    39  func (t *TestMultisigTopology) ChainID() string {
    40  	return "12"
    41  }
    42  
    43  func (t *TestMultisigTopology) IsSigner(address string) bool {
    44  	_, ok := t.validators[address]
    45  	return ok
    46  }
    47  
    48  func (t *TestMultisigTopology) ExcessSigners(addresses []string) bool {
    49  	if len(t.validators) > len(addresses) {
    50  		return true
    51  	}
    52  
    53  	m := make(map[string]struct{}, len(addresses))
    54  	for _, v := range addresses {
    55  		m[v] = struct{}{}
    56  	}
    57  
    58  	for k := range t.validators {
    59  		if _, ok := m[k]; !ok {
    60  			return true
    61  		}
    62  	}
    63  	return false
    64  }
    65  
    66  func (t *TestMultisigTopology) GetSigners() []string {
    67  	signers := make([]string, 0, len(t.validators))
    68  	for k := range t.validators {
    69  		signers = append(signers, k)
    70  	}
    71  	return signers
    72  }
    73  
    74  func (t *TestMultisigTopology) GetThreshold() uint32 {
    75  	return 666
    76  }
    77  
    78  func TestScores(t *testing.T) {
    79  	t.Run("test calculation of stake score with no anti-whaling", testStakeScore)
    80  	t.Run("test calculation of performance score", testPerformanceScore)
    81  	t.Run("test calculation of ranking score from stake and performance scores", testRankingScoreInternal)
    82  	t.Run("test calculation of ranking score from delegation data and validators state", testRankingScore)
    83  	t.Run("test score normalisation", testNormalisedScores)
    84  	t.Run("test validator score with anti whaling", testValidatorScore)
    85  	t.Run("test composition of raw validator score for rewards with performance score", testGetValScore)
    86  	t.Run("test multisig score", testGetMultisigScore)
    87  	t.Run("test multisig score more validators than signers", TestGetMultisigScoreMoreValidatorsThanSigners)
    88  	t.Run("test calculate tm rewards scores", testCalculateTMScores)
    89  	t.Run("test calculate ersatz rewards scores", testCalculateErsatzScores)
    90  	t.Run("test calculate rewards scores", testGetRewardsScores)
    91  }
    92  
    93  func testStakeScore(t *testing.T) {
    94  	validatorData := []*types.ValidatorData{
    95  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
    96  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
    97  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
    98  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
    99  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
   100  	}
   101  
   102  	// node1 has 10000 / 60000 = 0.1666666667
   103  	// node2 has 5000 / 60000 = 0.08333333333
   104  	// node3 has 10000 / 60000 = 0.1666666667
   105  	// node4 has 15000 / 60000 = 0.25
   106  	// node5 has 20000 / 60000 = 0.3333333333
   107  	scores := getStakeScore(validatorData)
   108  	require.Equal(t, "0.1666666666666667", scores["node1"].String())
   109  	require.Equal(t, "0.0833333333333333", scores["node2"].String())
   110  	require.Equal(t, "0.1666666666666667", scores["node3"].String())
   111  	require.Equal(t, "0.25", scores["node4"].String())
   112  	require.Equal(t, "0.3333333333333333", scores["node5"].String())
   113  }
   114  
   115  func testPerformanceScore(t *testing.T) {
   116  	topology := &Topology{}
   117  	topology.log = logging.NewTestLogger()
   118  	topology.validators = map[string]*valState{}
   119  	delegation := []*types.ValidatorData{
   120  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
   121  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
   122  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
   123  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
   124  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
   125  	}
   126  
   127  	// node1 has less than the minimum self stake => 0
   128  	// node2 is a tendermint validator and gets a performance score of 0.8
   129  	// node3 is pending and hasn't forwarded yet 3 events
   130  	// node4 is pending and hasn't voted yet for 3 events
   131  	// node5 is in the waiting list and has signed 9 of the 10 expected messages
   132  
   133  	topology.validators["node1"] = &valState{
   134  		data: ValidatorData{
   135  			ID: "node1",
   136  		},
   137  		heartbeatTracker: &validatorHeartbeatTracker{},
   138  	}
   139  	topology.validators["node2"] = &valState{
   140  		data: ValidatorData{
   141  			ID: "node2",
   142  		},
   143  		status:           ValidatorStatusTendermint,
   144  		heartbeatTracker: &validatorHeartbeatTracker{},
   145  	}
   146  	topology.validators["node3"] = &valState{
   147  		data: ValidatorData{
   148  			ID: "node3",
   149  		},
   150  		status:                          ValidatorStatusPending,
   151  		numberOfEthereumEventsForwarded: 2,
   152  		heartbeatTracker:                &validatorHeartbeatTracker{},
   153  	}
   154  	topology.validators["node4"] = &valState{
   155  		data: ValidatorData{
   156  			ID: "node4",
   157  		},
   158  		status:                          ValidatorStatusPending,
   159  		numberOfEthereumEventsForwarded: 4,
   160  		heartbeatTracker:                &validatorHeartbeatTracker{},
   161  	}
   162  	topology.validators["node5"] = &valState{
   163  		data: ValidatorData{
   164  			ID: "node5",
   165  		},
   166  		status:                          ValidatorStatusPending,
   167  		numberOfEthereumEventsForwarded: 4,
   168  		heartbeatTracker: &validatorHeartbeatTracker{
   169  			blockSigs: [10]bool{false, true, true, true, true, true, true, true, true, true},
   170  		},
   171  	}
   172  
   173  	topology.minimumStake = num.NewUint(3000)
   174  	topology.validatorPerformance = &MockPerformanceScore{}
   175  
   176  	scores := topology.getPerformanceScore(delegation)
   177  
   178  	require.Equal(t, "0", scores["node1"].String())
   179  	require.Equal(t, "0.8", scores["node2"].String())
   180  	require.Equal(t, "0", scores["node3"].String())
   181  	require.Equal(t, "0", scores["node4"].String())
   182  	require.Equal(t, "0.9", scores["node5"].String())
   183  }
   184  
   185  func testRankingScoreInternal(t *testing.T) {
   186  	stakeScores := map[string]num.Decimal{
   187  		"node1": num.DecimalFromFloat(0.1),
   188  		"node2": num.DecimalFromFloat(0.15),
   189  		"node3": num.DecimalFromFloat(0.2),
   190  		"node4": num.DecimalFromFloat(0.25),
   191  		"node5": num.DecimalFromFloat(0.3),
   192  	}
   193  	perfScores := map[string]num.Decimal{
   194  		"node1": num.DecimalZero(),
   195  		"node2": num.DecimalFromFloat(0.5),
   196  		"node3": num.DecimalFromFloat(0.9),
   197  		"node4": num.DecimalFromFloat(0.2),
   198  		"node5": num.DecimalFromFloat(1),
   199  	}
   200  
   201  	topology := &Topology{}
   202  	topology.log = logging.NewTestLogger()
   203  	topology.validators = map[string]*valState{}
   204  	topology.validators["node1"] = &valState{
   205  		data: ValidatorData{
   206  			ID: "node1",
   207  		},
   208  		status:           ValidatorStatusPending,
   209  		heartbeatTracker: &validatorHeartbeatTracker{},
   210  	}
   211  	topology.validators["node2"] = &valState{
   212  		data: ValidatorData{
   213  			ID: "node2",
   214  		},
   215  		status:           ValidatorStatusTendermint,
   216  		heartbeatTracker: &validatorHeartbeatTracker{},
   217  	}
   218  	topology.validators["node3"] = &valState{
   219  		data: ValidatorData{
   220  			ID: "node3",
   221  		},
   222  		status:           ValidatorStatusPending,
   223  		heartbeatTracker: &validatorHeartbeatTracker{},
   224  	}
   225  	topology.validators["node4"] = &valState{
   226  		data: ValidatorData{
   227  			ID: "node4",
   228  		},
   229  		status:           ValidatorStatusErsatz,
   230  		heartbeatTracker: &validatorHeartbeatTracker{},
   231  	}
   232  	topology.validators["node5"] = &valState{
   233  		data: ValidatorData{
   234  			ID: "node5",
   235  		},
   236  		status:           ValidatorStatusErsatz,
   237  		heartbeatTracker: &validatorHeartbeatTracker{},
   238  	}
   239  
   240  	topology.validatorIncumbentBonusFactor = num.DecimalFromFloat(1.1)
   241  	rankingScores := topology.getRankingScoreInternal(stakeScores, perfScores)
   242  
   243  	// 0.1 * 0 = 0
   244  	require.Equal(t, "0", rankingScores["node1"].String())
   245  	// 0.15 * 0.5 * 1.1 = 0.0825
   246  	require.Equal(t, "0.0825", rankingScores["node2"].String())
   247  	// 0.2 * 0.9 = 0.18
   248  	require.Equal(t, "0.18", rankingScores["node3"].String())
   249  	// 0.25 * 0.2 * 1.1 = 0.055
   250  	require.Equal(t, "0.055", rankingScores["node4"].String())
   251  	// 0.3 * 1 * 1.1 = 0.33
   252  	require.Equal(t, "0.33", rankingScores["node5"].String())
   253  }
   254  
   255  func testRankingScore(t *testing.T) {
   256  	topology := &Topology{}
   257  	topology.log = logging.NewTestLogger()
   258  	topology.validators = map[string]*valState{}
   259  	delegation := []*types.ValidatorData{
   260  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
   261  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
   262  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
   263  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
   264  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
   265  	}
   266  
   267  	// node1 has less than the minimum self stake => 0
   268  	// node2 is a tendermint validator and gets a performance score of 0.8
   269  	// node3 is pending and hasn't forwarded yet 3 events
   270  	// node4 is pending and hasn't voted yet for 3 events
   271  	// node5 is in the waiting list and has signed 9 of the 10 expected messages
   272  
   273  	topology.validators["node1"] = &valState{
   274  		data: ValidatorData{
   275  			ID: "node1",
   276  		},
   277  		status:           ValidatorStatusPending,
   278  		heartbeatTracker: &validatorHeartbeatTracker{},
   279  	}
   280  	topology.validators["node2"] = &valState{
   281  		data: ValidatorData{
   282  			ID: "node2",
   283  		},
   284  		status:           ValidatorStatusTendermint,
   285  		heartbeatTracker: &validatorHeartbeatTracker{},
   286  	}
   287  	topology.validators["node3"] = &valState{
   288  		data: ValidatorData{
   289  			ID: "node3",
   290  		},
   291  		status:                          ValidatorStatusErsatz,
   292  		numberOfEthereumEventsForwarded: 4,
   293  		heartbeatTracker: &validatorHeartbeatTracker{
   294  			blockSigs: [10]bool{false, false, true, false, true, false, true, true, true, true},
   295  		},
   296  	}
   297  	topology.validators["node4"] = &valState{
   298  		data: ValidatorData{
   299  			ID: "node4",
   300  		},
   301  		status:                          ValidatorStatusPending,
   302  		numberOfEthereumEventsForwarded: 4,
   303  		heartbeatTracker:                &validatorHeartbeatTracker{},
   304  	}
   305  	topology.validators["node5"] = &valState{
   306  		data: ValidatorData{
   307  			ID: "node5",
   308  		},
   309  		status:           ValidatorStatusTendermint,
   310  		heartbeatTracker: &validatorHeartbeatTracker{},
   311  	}
   312  
   313  	topology.minimumStake = num.NewUint(3000)
   314  	topology.validatorPerformance = &MockPerformanceScore{}
   315  	topology.validatorIncumbentBonusFactor = num.DecimalFromFloat(1.1)
   316  
   317  	stakeScores, perfScores, rankingScores := topology.getRankingScore(delegation)
   318  	require.Equal(t, "0.1666666666666667", stakeScores["node1"].String())
   319  	require.Equal(t, "0.0833333333333333", stakeScores["node2"].String())
   320  	require.Equal(t, "0.1666666666666667", stakeScores["node3"].String())
   321  	require.Equal(t, "0.25", stakeScores["node4"].String())
   322  	require.Equal(t, "0.3333333333333333", stakeScores["node5"].String())
   323  
   324  	// less than min self stake
   325  	require.Equal(t, "0", perfScores["node1"].String())
   326  	// tm validator performance = 0.8
   327  	require.Equal(t, "0.8", perfScores["node2"].String())
   328  	// ersatz signed 6/10 => performance = 0.6
   329  	require.Equal(t, "0.6", perfScores["node3"].String())
   330  	// pending - min requirements not met yet
   331  	require.Equal(t, "0", perfScores["node4"].String())
   332  	// tm validator performance = 0.8
   333  	require.Equal(t, "0.8", perfScores["node5"].String())
   334  
   335  	// ranking scores:
   336  	// 0.1666666666666667 * 0 = 0
   337  	require.Equal(t, "0", rankingScores["node1"].String())
   338  	// 0.0833333333333333*0.8*1.1 = 0.07333333333
   339  	require.Equal(t, "0.073333333333333304", rankingScores["node2"].String())
   340  	// 0.1666666666666667 * 0.6 * 1.1 = 0.11
   341  	require.Equal(t, "0.110000000000000022", rankingScores["node3"].String())
   342  	// 0.25 * 0 = 0
   343  	require.Equal(t, "0", rankingScores["node4"].String())
   344  	// 0.3333333333333333 * 1.1 * 0.8 = 0.2933333333
   345  	require.Equal(t, "0.293333333333333304", rankingScores["node5"].String())
   346  }
   347  
   348  func testNormalisedScores(t *testing.T) {
   349  	rnd := rand.New(rand.NewSource(100000))
   350  	scores := map[string]num.Decimal{
   351  		"node1": num.DecimalZero(),
   352  		"node2": num.DecimalFromFloat(0.073333333333333304),
   353  		"node3": num.DecimalFromFloat(0.110000000000000022),
   354  		"node4": num.DecimalZero(),
   355  		"node5": num.DecimalFromFloat(0.293333333333333304),
   356  	}
   357  	norm := normaliseScores(scores, rnd)
   358  	require.Equal(t, "0", norm["node1"].String())
   359  	require.Equal(t, "0.1538461538461538", norm["node2"].String())
   360  	require.Equal(t, "0.2307692307692308", norm["node3"].String())
   361  	require.Equal(t, "0", norm["node4"].String())
   362  	require.Equal(t, "0.6153846153846154", norm["node5"].String())
   363  
   364  	total := num.DecimalZero()
   365  	for _, d := range norm {
   366  		total = total.Add(d)
   367  	}
   368  	require.True(t, total.LessThanOrEqual(num.DecimalFromFloat(1)))
   369  }
   370  
   371  func testValidatorScore(t *testing.T) {
   372  	validatorStake := num.DecimalFromInt64(10000)
   373  	largeValidatorStake := num.DecimalFromInt64(40000)
   374  	extraLargeValidatorStake := num.DecimalFromInt64(60000)
   375  	extraExtraLargeValidatorStake := num.DecimalFromInt64(70000)
   376  	totalStake := num.DecimalFromInt64(100000.0)
   377  	minVal := num.DecimalFromInt64(5)
   378  	compLevel, _ := num.DecimalFromString("1.1")
   379  	optimalStakeMultiplier, _ := num.DecimalFromString("3.0")
   380  
   381  	stakeScoreParams := types.StakeScoreParams{
   382  		MinVal:                 minVal,
   383  		CompLevel:              compLevel,
   384  		OptimalStakeMultiplier: optimalStakeMultiplier,
   385  	}
   386  
   387  	// valStake = 10k, totalStake = 100k, optStake = 20k
   388  	// valScore = 0.1
   389  	require.Equal(t, "0.10", CalcValidatorScore(validatorStake, totalStake, num.DecimalFromInt64(20000), stakeScoreParams).StringFixed(2))
   390  
   391  	// valStake = 20k, totalStake = 100k, optStake = 20k
   392  	// valScore = 0.2
   393  	// no pentalty
   394  	require.Equal(t, "0.20", CalcValidatorScore(largeValidatorStake, totalStake, num.DecimalFromInt64(20000), stakeScoreParams).StringFixed(2))
   395  
   396  	// valStake = 60k, totalStake = 100k, optStake = 20k
   397  	// valScore = 0.2
   398  	// with flat pentalty
   399  	require.Equal(t, "0.20", CalcValidatorScore(extraLargeValidatorStake, totalStake, num.DecimalFromInt64(20000), stakeScoreParams).StringFixed(2))
   400  
   401  	// valStake = 70k, totalStake = 100k, optStake = 20k
   402  	// valScore = 0.1
   403  	// with flat and down pentalty
   404  	require.Equal(t, "0.10", CalcValidatorScore(extraExtraLargeValidatorStake, totalStake, num.DecimalFromInt64(20000), stakeScoreParams).StringFixed(2))
   405  
   406  	// no stake => 0
   407  	require.Equal(t, "0.00", CalcValidatorScore(num.DecimalZero(), num.DecimalZero(), num.DecimalFromInt64(20000), stakeScoreParams).StringFixed(2))
   408  }
   409  
   410  func testGetValScore(t *testing.T) {
   411  	stakeScore := map[string]num.Decimal{
   412  		"node1": num.DecimalFromFloat(0.1),
   413  		"node2": num.DecimalFromFloat(0.2),
   414  		"node3": num.DecimalFromFloat(0.3),
   415  		"node4": num.DecimalFromFloat(0.4),
   416  		"node5": num.DecimalFromFloat(0.5),
   417  	}
   418  	perfScore := map[string]num.Decimal{
   419  		"node1": num.DecimalFromFloat(0.5),
   420  		"node2": num.DecimalFromFloat(0.6),
   421  		"node3": num.DecimalFromFloat(0.7),
   422  		"node4": num.DecimalFromFloat(0.8),
   423  		"node5": num.DecimalFromFloat(0.9),
   424  	}
   425  
   426  	valScore := getValScore(stakeScore, perfScore)
   427  	require.Equal(t, "0.05", valScore["node1"].String())
   428  	require.Equal(t, "0.12", valScore["node2"].String())
   429  	require.Equal(t, "0.21", valScore["node3"].String())
   430  	require.Equal(t, "0.32", valScore["node4"].String())
   431  	require.Equal(t, "0.45", valScore["node5"].String())
   432  }
   433  
   434  func testGetMultisigScore(t *testing.T) {
   435  	stakeScore := map[string]num.Decimal{
   436  		"node1":  num.DecimalFromFloat(0.1),
   437  		"node2":  num.DecimalFromFloat(0.2),
   438  		"node3":  num.DecimalFromFloat(0.3),
   439  		"node4":  num.DecimalFromFloat(0.4),
   440  		"node5":  num.DecimalFromFloat(0.5),
   441  		"node6":  num.DecimalFromFloat(0.55),
   442  		"node7":  num.DecimalFromFloat(0.6),
   443  		"node8":  num.DecimalFromFloat(0.65),
   444  		"node9":  num.DecimalFromFloat(0.7),
   445  		"node10": num.DecimalFromFloat(0.75),
   446  	}
   447  	perfScore := map[string]num.Decimal{
   448  		"node1":  num.DecimalFromFloat(0.5),
   449  		"node2":  num.DecimalFromFloat(0.6),
   450  		"node3":  num.DecimalFromFloat(0.7),
   451  		"node4":  num.DecimalFromFloat(0.8),
   452  		"node5":  num.DecimalFromFloat(0.9),
   453  		"node6":  num.DecimalFromFloat(0.9),
   454  		"node7":  num.DecimalFromFloat(0.9),
   455  		"node8":  num.DecimalFromFloat(0.9),
   456  		"node9":  num.DecimalFromFloat(0.9),
   457  		"node10": num.DecimalFromFloat(0.9),
   458  	}
   459  
   460  	multisigValidators := map[string]struct{}{
   461  		"node1eth":  {},
   462  		"node2eth":  {},
   463  		"node5eth":  {},
   464  		"node7eth":  {},
   465  		"node8eth":  {},
   466  		"node9eth":  {},
   467  		"node10eth": {},
   468  	}
   469  
   470  	nodeIDToEthAddress := map[string]string{
   471  		"node1":  "node1eth",
   472  		"node2":  "node2eth",
   473  		"node3":  "node3eth",
   474  		"node4":  "node4eth",
   475  		"node5":  "node5eth",
   476  		"node6":  "node6eth",
   477  		"node7":  "node7eth",
   478  		"node8":  "node8eth",
   479  		"node9":  "node9eth",
   480  		"node10": "node10eth",
   481  	}
   482  
   483  	multisigValidators2 := map[string]struct{}{}
   484  	maps.Copy(multisigValidators2, multisigValidators)
   485  
   486  	mtop1 := &TestMultisigTopology{
   487  		validators: multisigValidators,
   488  	}
   489  	mtop2 := &TestMultisigTopology{
   490  		validators: multisigValidators2,
   491  	}
   492  
   493  	log := logging.NewTestLogger()
   494  	multisigScore := getMultisigScore(
   495  		log,
   496  		ValidatorStatusTendermint,
   497  		stakeScore, perfScore, mtop1, mtop2, 5,
   498  		nodeIDToEthAddress,
   499  	)
   500  
   501  	// sorted by the score = stake x performance node 10 is the top and node 1 is the bottom.
   502  	// looking at the top 5 that gives node10 - node6
   503  	// out of those node 10,9,8,7 are in the multisig set
   504  	// node 6 is not so it gets a multisig score of 0
   505  	// all the other nodes are not required to be so their multisig score is 1.
   506  	require.Equal(t, "1", multisigScore["node1"].String())
   507  	require.Equal(t, "1", multisigScore["node2"].String())
   508  	require.Equal(t, "1", multisigScore["node3"].String())
   509  	require.Equal(t, "1", multisigScore["node4"].String())
   510  	require.Equal(t, "1", multisigScore["node5"].String())
   511  	require.Equal(t, "0", multisigScore["node6"].String())
   512  	require.Equal(t, "1", multisigScore["node7"].String())
   513  	require.Equal(t, "1", multisigScore["node8"].String())
   514  	require.Equal(t, "1", multisigScore["node9"].String())
   515  	require.Equal(t, "1", multisigScore["node10"].String())
   516  
   517  	// node 6 is added to one bridge but not the other
   518  	multisigValidators["node6"] = struct{}{}
   519  	multisigScore = getMultisigScore(
   520  		log,
   521  		ValidatorStatusTendermint,
   522  		stakeScore, perfScore, mtop1, mtop2, 5,
   523  		nodeIDToEthAddress,
   524  	)
   525  	require.Equal(t, "0", multisigScore["node6"].String())
   526  
   527  	// node6 is added to the second bridge
   528  	multisigValidators2["node6"] = struct{}{}
   529  	multisigScore = getMultisigScore(
   530  		log,
   531  		ValidatorStatusTendermint,
   532  		stakeScore, perfScore, mtop1, mtop2, 5,
   533  		nodeIDToEthAddress,
   534  	)
   535  	require.Equal(t, "0", multisigScore["node6"].String())
   536  
   537  	// Add a node to *one* bridge that shouldn't be there, even if its not on the other one
   538  	// all scores should be zero
   539  	multisigValidators["node100"] = struct{}{}
   540  	nodeIDToEthAddress["node100"] = "node100eth"
   541  
   542  	// everyone gets zero scores because there is someone on there who shouldn't be
   543  	multisigScore = getMultisigScore(log, ValidatorStatusTendermint, stakeScore, perfScore, mtop1, mtop2, 5, nodeIDToEthAddress)
   544  	require.Equal(t, "0", multisigScore["node1"].String())
   545  	require.Equal(t, "0", multisigScore["node2"].String())
   546  	require.Equal(t, "0", multisigScore["node3"].String())
   547  	require.Equal(t, "0", multisigScore["node4"].String())
   548  	require.Equal(t, "0", multisigScore["node5"].String())
   549  	require.Equal(t, "0", multisigScore["node6"].String())
   550  	require.Equal(t, "0", multisigScore["node7"].String())
   551  	require.Equal(t, "0", multisigScore["node8"].String())
   552  	require.Equal(t, "0", multisigScore["node9"].String())
   553  	require.Equal(t, "0", multisigScore["node10"].String())
   554  }
   555  
   556  func TestGetMultisigScoreMoreValidatorsThanSigners(t *testing.T) {
   557  	// 5 nodes all with an equal score, and none of them on the contract. We also set the number of signers we check to only 2
   558  	// normally in this case we check the 2 nodes with the highest score, but when they are all equal we *should* instead sort
   559  	// by nodeID
   560  	nEthMultisigSigners := 2
   561  	stakeScore := map[string]num.Decimal{
   562  		"node1": num.DecimalFromFloat(0.1),
   563  		"node2": num.DecimalFromFloat(0.1),
   564  		"node3": num.DecimalFromFloat(0.1),
   565  		"node4": num.DecimalFromFloat(0.1),
   566  		"node5": num.DecimalFromFloat(0.1),
   567  	}
   568  	perfScore := map[string]num.Decimal{
   569  		"node1": num.DecimalFromFloat(0.1),
   570  		"node2": num.DecimalFromFloat(0.1),
   571  		"node3": num.DecimalFromFloat(0.1),
   572  		"node4": num.DecimalFromFloat(0.1),
   573  		"node5": num.DecimalFromFloat(0.1),
   574  	}
   575  
   576  	nodeIDToEthAddress := map[string]string{
   577  		"node1": "node1eth",
   578  		"node2": "node2eth",
   579  		"node3": "node3eth",
   580  		"node4": "node4eth",
   581  		"node5": "node5eth",
   582  	}
   583  
   584  	mtop1 := &TestMultisigTopology{
   585  		validators: map[string]struct{}{},
   586  	}
   587  	mtop2 := &TestMultisigTopology{
   588  		validators: map[string]struct{}{},
   589  	}
   590  
   591  	log := logging.NewTestLogger()
   592  
   593  	for i := 0; i < 100; i++ {
   594  		multisigScore := getMultisigScore(
   595  			log,
   596  			ValidatorStatusTendermint,
   597  			stakeScore, perfScore, mtop1, mtop2, nEthMultisigSigners,
   598  			nodeIDToEthAddress,
   599  		)
   600  		require.Equal(t, "0", multisigScore["node1"].String())
   601  		require.Equal(t, "0", multisigScore["node2"].String())
   602  		require.Equal(t, "1", multisigScore["node3"].String())
   603  		require.Equal(t, "1", multisigScore["node4"].String())
   604  		require.Equal(t, "1", multisigScore["node5"].String())
   605  	}
   606  }
   607  
   608  func testCalculateTMScores(t *testing.T) {
   609  	topology := &Topology{}
   610  	topology.validators = map[string]*valState{}
   611  	topology.log = logging.NewTestLogger()
   612  
   613  	for i := 0; i < 10; i++ {
   614  		index := num.NewUint(uint64(i) + 1).String()
   615  		topology.validators["node"+index] = &valState{
   616  			data: ValidatorData{
   617  				ID:              "node" + index,
   618  				TmPubKey:        "key" + index,
   619  				EthereumAddress: "node" + index + "eth",
   620  			},
   621  			status:           ValidatorStatusTendermint,
   622  			heartbeatTracker: &validatorHeartbeatTracker{},
   623  		}
   624  	}
   625  	topology.validators["node11"] = &valState{
   626  		data: ValidatorData{
   627  			ID:              "node11",
   628  			EthereumAddress: "node11eth",
   629  		},
   630  		status:           ValidatorStatusErsatz,
   631  		heartbeatTracker: &validatorHeartbeatTracker{},
   632  	}
   633  	topology.validators["node12"] = &valState{
   634  		data: ValidatorData{
   635  			ID:              "node12",
   636  			EthereumAddress: "node12eth",
   637  		},
   638  		status:           ValidatorStatusErsatz,
   639  		heartbeatTracker: &validatorHeartbeatTracker{},
   640  	}
   641  
   642  	topology.validatorIncumbentBonusFactor = num.DecimalFromFloat(1.1)
   643  	topology.minimumStake = num.NewUint(3000)
   644  	topology.validatorPerformance = &MockPerformanceScore{}
   645  	topology.numberEthMultisigSigners = 7
   646  
   647  	mtop1 := &TestMultisigTopology{}
   648  	mtop1.validators = map[string]struct{}{
   649  		"node1eth": {},
   650  		"node2eth": {},
   651  		"node3eth": {},
   652  		"node5eth": {},
   653  		"node7eth": {},
   654  		"node9eth": {},
   655  	}
   656  	mtop2 := &TestMultisigTopology{}
   657  	mtop2.validators = map[string]struct{}{
   658  		"node1eth": {},
   659  		"node2eth": {},
   660  		"node3eth": {},
   661  		"node5eth": {},
   662  		"node7eth": {},
   663  		"node9eth": {},
   664  	}
   665  	topology.primaryMultisig = mtop1
   666  	topology.secondaryMultisig = mtop2
   667  
   668  	delegation := []*types.ValidatorData{
   669  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
   670  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
   671  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
   672  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
   673  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
   674  		{NodeID: "node6", PubKey: "node6PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key6"},
   675  		{NodeID: "node7", PubKey: "node7PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(6000), Delegators: map[string]*num.Uint{}, TmPubKey: "key7"},
   676  		{NodeID: "node8", PubKey: "node8PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(5000), Delegators: map[string]*num.Uint{}, TmPubKey: "key8"},
   677  		{NodeID: "node9", PubKey: "node9PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(4000), Delegators: map[string]*num.Uint{}, TmPubKey: "key9"},
   678  		{NodeID: "node10", PubKey: "node10PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key10"},
   679  		{NodeID: "node11", PubKey: "node11PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key11"},
   680  		{NodeID: "node12", PubKey: "node12PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(1000), Delegators: map[string]*num.Uint{}, TmPubKey: "key12"},
   681  	}
   682  	scoreData, _ := topology.calculateScores(delegation, ValidatorStatusTendermint, types.StakeScoreParams{MinVal: num.DecimalFromFloat(5), CompLevel: num.DecimalFromFloat(3.3), OptimalStakeMultiplier: num.DecimalFromFloat(3)}, nil)
   683  
   684  	require.Equal(t, 10, len(scoreData.RawValScores))
   685  	require.Equal(t, 10, len(scoreData.PerformanceScores))
   686  	require.Equal(t, 10, len(scoreData.MultisigScores))
   687  	require.Equal(t, 10, len(scoreData.ValScores))
   688  	require.Equal(t, 10, len(scoreData.NormalisedScores))
   689  
   690  	// raw scores
   691  	// total = 110000
   692  	// node1 = 10000/110000 = 0.09090909091
   693  	// node2 = 5000/110000 = 0.04545454545
   694  	// node3 = 10000/110000 = 0.09090909091
   695  	// node4 = 15000/110000 = 0.1363636364
   696  	// node5 = 20000/110000 = 0.1818181818
   697  	// node6 = 12000/110000 = 0.1090909091
   698  	// node7 = 11000/110000 = 0.1
   699  	// node8 = 10000/110000 = 0.09090909091
   700  	// node9 = 9000/110000 = 0.08181818182
   701  	// node10 = 8000/110000 = 0.07272727273
   702  	require.Equal(t, "0.09090909", scoreData.RawValScores["node1"].StringFixed(8))
   703  	require.Equal(t, "0.04545455", scoreData.RawValScores["node2"].StringFixed(8))
   704  	require.Equal(t, "0.09090909", scoreData.RawValScores["node3"].StringFixed(8))
   705  	require.Equal(t, "0.13636364", scoreData.RawValScores["node4"].StringFixed(8))
   706  	require.Equal(t, "0.18181818", scoreData.RawValScores["node5"].StringFixed(8))
   707  	require.Equal(t, "0.10909091", scoreData.RawValScores["node6"].StringFixed(8))
   708  	require.Equal(t, "0.10000000", scoreData.RawValScores["node7"].StringFixed(8))
   709  	require.Equal(t, "0.09090909", scoreData.RawValScores["node8"].StringFixed(8))
   710  	require.Equal(t, "0.08181818", scoreData.RawValScores["node9"].StringFixed(8))
   711  	require.Equal(t, "0.07272727", scoreData.RawValScores["node10"].StringFixed(8))
   712  
   713  	// performance score
   714  	// node1 has less than the minimum self stake => 0
   715  	// node2-5 0.8
   716  	// node6 0.3
   717  	// node7 0.7
   718  	// node8 0.3
   719  	// node9 0.7
   720  	// node10 1
   721  	require.Equal(t, "0", scoreData.PerformanceScores["node1"].String())
   722  	require.Equal(t, "0.8", scoreData.PerformanceScores["node2"].String())
   723  	require.Equal(t, "0.8", scoreData.PerformanceScores["node3"].String())
   724  	require.Equal(t, "0.8", scoreData.PerformanceScores["node4"].String())
   725  	require.Equal(t, "0.8", scoreData.PerformanceScores["node5"].String())
   726  	require.Equal(t, "0.3", scoreData.PerformanceScores["node6"].String())
   727  	require.Equal(t, "0.7", scoreData.PerformanceScores["node7"].String())
   728  	require.Equal(t, "0.3", scoreData.PerformanceScores["node8"].String())
   729  	require.Equal(t, "0.7", scoreData.PerformanceScores["node9"].String())
   730  	require.Equal(t, "1", scoreData.PerformanceScores["node10"].String())
   731  
   732  	// multisig score
   733  	// stake_score x performance_score:
   734  	// node1 = 0
   735  	// node2 = 0.04545454545 * 0.8 = 0.03636363636
   736  	// node3= 0.09090909091 * 0.8 = 0.07272727273
   737  	// node4 = 0.1363636364 * 0.8 = 0.1090909091
   738  	// node5 = 0.1818181818 * 0.8 = 0.1454545454
   739  	// node6 = 0.1090909091 * 0.3 = 0.03272727273
   740  	// node7 = 0.1 * 0.7 = 0.07
   741  	// node8 = 0.09090909091 * 0.3 = 0.02727272727
   742  	// node9 = 0.08181818182 * 0.7 = 0.05727272727
   743  	// node10 = 0.07272727273 * 1 = 0.07272727273
   744  	// sorted order is:
   745  	// node5, node4, node3, node10, node7, node9, node2, node6, node8, node1
   746  	// the net param is set to 7 so we're looking at the top 7 scores
   747  	require.Equal(t, "1", scoreData.MultisigScores["node1"].String())
   748  	require.Equal(t, "1", scoreData.MultisigScores["node2"].String())
   749  	require.Equal(t, "1", scoreData.MultisigScores["node3"].String())
   750  	require.Equal(t, "0", scoreData.MultisigScores["node4"].String())
   751  	require.Equal(t, "1", scoreData.MultisigScores["node5"].String())
   752  	require.Equal(t, "1", scoreData.MultisigScores["node6"].String())
   753  	require.Equal(t, "1", scoreData.MultisigScores["node7"].String())
   754  	require.Equal(t, "1", scoreData.MultisigScores["node8"].String())
   755  	require.Equal(t, "1", scoreData.MultisigScores["node9"].String())
   756  	require.Equal(t, "0", scoreData.MultisigScores["node10"].String())
   757  
   758  	// val scores = stake_score * perf_score * multisig_score
   759  	require.Equal(t, "0", scoreData.ValScores["node1"].String())
   760  	require.Equal(t, "0.03636363636", scoreData.ValScores["node2"].StringFixed(11))
   761  	require.Equal(t, "0.07272727273", scoreData.ValScores["node3"].StringFixed(11))
   762  	require.Equal(t, "0", scoreData.ValScores["node4"].String())
   763  	require.Equal(t, "0.14545454545", scoreData.ValScores["node5"].StringFixed(11))
   764  	require.Equal(t, "0.03272727272727273", scoreData.ValScores["node6"].String())
   765  	require.Equal(t, "0.07", scoreData.ValScores["node7"].StringFixed(2))
   766  	require.Equal(t, "0.02727272727272727", scoreData.ValScores["node8"].String())
   767  	require.Equal(t, "0.05727272727", scoreData.ValScores["node9"].StringFixed(11))
   768  	require.Equal(t, "0", scoreData.ValScores["node10"].String())
   769  
   770  	// normalised scores
   771  	// node2 = 0.03636363636 / 0.3818181818 = 0.09523809523
   772  	// node3 = 0.07272727273 / 0.3818181818 = 0.1904761905
   773  	// node5 = 0.14545454545 / 0.3818181818 = 0.380952381
   774  	// node7 = 0.07 / 0.3818181818 = 0.1833333333
   775  	// node9 = 0.05727272727 / 0.3818181818 = 0.15
   776  	require.Equal(t, "0.08230452675", scoreData.NormalisedScores["node2"].StringFixed(11))
   777  	require.Equal(t, "0.16460905350", scoreData.NormalisedScores["node3"].StringFixed(11))
   778  	require.Equal(t, "0.32921810700", scoreData.NormalisedScores["node5"].StringFixed(11))
   779  	require.Equal(t, "0.15843621399", scoreData.NormalisedScores["node7"].StringFixed(11))
   780  	require.Equal(t, "0.13", scoreData.NormalisedScores["node9"].StringFixed(2))
   781  
   782  	totalNormScore := num.DecimalZero()
   783  	for _, d := range scoreData.NormalisedScores {
   784  		totalNormScore = totalNormScore.Add(d)
   785  	}
   786  	require.True(t, totalNormScore.LessThanOrEqual(decimalOne))
   787  }
   788  
   789  func testCalculateErsatzScores(t *testing.T) {
   790  	topology := &Topology{}
   791  	topology.log = logging.NewTestLogger()
   792  	topology.validators = map[string]*valState{}
   793  
   794  	for i := 0; i < 10; i++ {
   795  		index := num.NewUint(uint64(i) + 1).String()
   796  		topology.validators["node"+index] = &valState{
   797  			data: ValidatorData{
   798  				ID:              "node" + index,
   799  				EthereumAddress: "node" + index + "eth",
   800  			},
   801  			status:                          ValidatorStatusErsatz,
   802  			heartbeatTracker:                &validatorHeartbeatTracker{},
   803  			numberOfEthereumEventsForwarded: 4,
   804  		}
   805  		for j := 0; j < i; j++ {
   806  			topology.validators["node"+index].heartbeatTracker.blockSigs[j] = true
   807  		}
   808  	}
   809  	topology.validators["node11"] = &valState{
   810  		data: ValidatorData{
   811  			ID:              "node11",
   812  			EthereumAddress: "node11eth",
   813  		},
   814  		status:           ValidatorStatusTendermint,
   815  		heartbeatTracker: &validatorHeartbeatTracker{},
   816  	}
   817  	topology.validators["node12"] = &valState{
   818  		data: ValidatorData{
   819  			ID:              "node12",
   820  			EthereumAddress: "node12eth",
   821  		},
   822  		status:           ValidatorStatusTendermint,
   823  		heartbeatTracker: &validatorHeartbeatTracker{},
   824  	}
   825  
   826  	topology.validatorIncumbentBonusFactor = num.DecimalFromFloat(1.1)
   827  	topology.minimumStake = num.NewUint(3000)
   828  	topology.validatorPerformance = &MockPerformanceScore{}
   829  	topology.numberEthMultisigSigners = 7
   830  	topology.primaryMultisig = &TestMultisigTopology{
   831  		validators: map[string]struct{}{
   832  			"node1eth": {},
   833  			"node2eth": {},
   834  			"node3eth": {},
   835  			"node5eth": {},
   836  			"node7eth": {},
   837  			"node9eth": {},
   838  		},
   839  	}
   840  
   841  	delegation := []*types.ValidatorData{
   842  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
   843  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
   844  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
   845  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
   846  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
   847  		{NodeID: "node6", PubKey: "node6PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key6"},
   848  		{NodeID: "node7", PubKey: "node7PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(6000), Delegators: map[string]*num.Uint{}, TmPubKey: "key7"},
   849  		{NodeID: "node8", PubKey: "node8PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(5000), Delegators: map[string]*num.Uint{}, TmPubKey: "key8"},
   850  		{NodeID: "node9", PubKey: "node9PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(4000), Delegators: map[string]*num.Uint{}, TmPubKey: "key9"},
   851  		{NodeID: "node10", PubKey: "node10PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key10"},
   852  		{NodeID: "node11", PubKey: "node11PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key11"},
   853  		{NodeID: "node12", PubKey: "node12PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(1000), Delegators: map[string]*num.Uint{}, TmPubKey: "key12"},
   854  	}
   855  	topology.rng = rand.New(rand.NewSource(100000))
   856  	optimalScore := num.DecimalFromInt64(10000)
   857  	scoreData, _ := topology.calculateScores(delegation, ValidatorStatusErsatz, types.StakeScoreParams{MinVal: num.DecimalFromFloat(5), CompLevel: num.DecimalFromFloat(3.3), OptimalStakeMultiplier: num.DecimalFromFloat(5)}, &optimalScore)
   858  
   859  	require.Equal(t, 10, len(scoreData.RawValScores))
   860  	require.Equal(t, 10, len(scoreData.PerformanceScores))
   861  	require.Equal(t, 10, len(scoreData.MultisigScores))
   862  	require.Equal(t, 10, len(scoreData.ValScores))
   863  	require.Equal(t, 10, len(scoreData.NormalisedScores))
   864  
   865  	// raw scores
   866  	// total = 110000
   867  	// opt stake = 10000
   868  	// node1 = 10000/110000 = 0.09090909091
   869  	// node2 = 5000/110000 = 0.04545454545
   870  	// node3 = 10000/110000 = 0.09090909091
   871  	// node4 = 15000/110000 = 10000/110000 = 0.09090909091 (with flat penalty)
   872  	// node5 = 20000/110000 = 10000/110000 = 0.09090909091 (with flat penalty)
   873  	// node6 = 12000/110000 = 10000/110000 = 0.09090909091 (with flat penalty)
   874  	// node7 = 11000/110000 = 10000/110000 = 0.09090909091 (with flat penalty)
   875  	// node8 = 10000/110000 = 0.09090909091
   876  	// node9 = 9000/110000 = 0.08181818182
   877  	// node10 = 8000/110000 = 0.07272727273
   878  	require.Equal(t, "0.09090909", scoreData.RawValScores["node1"].StringFixed(8))
   879  	require.Equal(t, "0.04545455", scoreData.RawValScores["node2"].StringFixed(8))
   880  	require.Equal(t, "0.09090909", scoreData.RawValScores["node3"].StringFixed(8))
   881  	require.Equal(t, "0.09090909", scoreData.RawValScores["node4"].StringFixed(8))
   882  	require.Equal(t, "0.09090909", scoreData.RawValScores["node5"].StringFixed(8))
   883  	require.Equal(t, "0.09090909", scoreData.RawValScores["node6"].StringFixed(8))
   884  	require.Equal(t, "0.09090909", scoreData.RawValScores["node7"].StringFixed(8))
   885  	require.Equal(t, "0.09090909", scoreData.RawValScores["node8"].StringFixed(8))
   886  	require.Equal(t, "0.08181818", scoreData.RawValScores["node9"].StringFixed(8))
   887  	require.Equal(t, "0.07272727", scoreData.RawValScores["node10"].StringFixed(8))
   888  
   889  	// performance score
   890  	// node1 0
   891  	// node2 0.1
   892  	// node3 0.2
   893  	// node4 0.3
   894  	// node5 0.4
   895  	// node6 0.5
   896  	// node7 0.6
   897  	// node8 0.7
   898  	// node9 0.8
   899  	// node10 0.9
   900  	require.Equal(t, "0", scoreData.PerformanceScores["node1"].String())
   901  	require.Equal(t, "0.1", scoreData.PerformanceScores["node2"].String())
   902  	require.Equal(t, "0.2", scoreData.PerformanceScores["node3"].String())
   903  	require.Equal(t, "0.3", scoreData.PerformanceScores["node4"].String())
   904  	require.Equal(t, "0.4", scoreData.PerformanceScores["node5"].String())
   905  	require.Equal(t, "0.5", scoreData.PerformanceScores["node6"].String())
   906  	require.Equal(t, "0.6", scoreData.PerformanceScores["node7"].String())
   907  	require.Equal(t, "0.7", scoreData.PerformanceScores["node8"].String())
   908  	require.Equal(t, "0.8", scoreData.PerformanceScores["node9"].String())
   909  	require.Equal(t, "0.9", scoreData.PerformanceScores["node10"].String())
   910  
   911  	// multisig score
   912  	// not relevant for ersatz validators should all be 1
   913  	require.Equal(t, "1", scoreData.MultisigScores["node1"].String())
   914  	require.Equal(t, "1", scoreData.MultisigScores["node2"].String())
   915  	require.Equal(t, "1", scoreData.MultisigScores["node3"].String())
   916  	require.Equal(t, "1", scoreData.MultisigScores["node4"].String())
   917  	require.Equal(t, "1", scoreData.MultisigScores["node5"].String())
   918  	require.Equal(t, "1", scoreData.MultisigScores["node6"].String())
   919  	require.Equal(t, "1", scoreData.MultisigScores["node7"].String())
   920  	require.Equal(t, "1", scoreData.MultisigScores["node8"].String())
   921  	require.Equal(t, "1", scoreData.MultisigScores["node9"].String())
   922  	require.Equal(t, "1", scoreData.MultisigScores["node10"].String())
   923  
   924  	// val score = stake_score x performance_score:
   925  	// node1 = 0
   926  	// node2 = 0.04545454545 * 0.1 = 0.004545454545
   927  	// node3 = 0.09090909091 * 0.2 = 0.01818181818
   928  	// node4 = 0.09090909091 * 0.3 = 0.02727272727
   929  	// node5 = 0.09090909091 * 0.4 = 0.03636363636
   930  	// node6 = 0.09090909091 * 0.5 = 0.04545454545
   931  	// node7 = 0.09090909091 * 0.6 = 0.05454545455
   932  	// node8 = 0.09090909091 * 0.7 = 0.06363636364
   933  	// node9 = 0.08181818182 * 0.8 = 0.06545454545
   934  	// node10 = 0.07272727273 * 0.9 = 0.06545454545
   935  
   936  	// val scores = stake_score * perf_score * multisig_score
   937  	require.Equal(t, "0", scoreData.ValScores["node1"].String())
   938  	require.Equal(t, "0.00454545455", scoreData.ValScores["node2"].StringFixed(11))
   939  	require.Equal(t, "0.01818181818", scoreData.ValScores["node3"].StringFixed(11))
   940  	require.Equal(t, "0.02727272727", scoreData.ValScores["node4"].StringFixed(11))
   941  	require.Equal(t, "0.03636363636", scoreData.ValScores["node5"].StringFixed(11))
   942  	require.Equal(t, "0.04545454545", scoreData.ValScores["node6"].StringFixed(11))
   943  	require.Equal(t, "0.05454545455", scoreData.ValScores["node7"].StringFixed(11))
   944  	require.Equal(t, "0.06363636364", scoreData.ValScores["node8"].StringFixed(11))
   945  	require.Equal(t, "0.06545454545", scoreData.ValScores["node9"].StringFixed(11))
   946  	require.Equal(t, "0.06545454545", scoreData.ValScores["node10"].StringFixed(11))
   947  
   948  	// normalised scores
   949  	// node1 = 0
   950  	// node2 = 0.00454545455 / 0.3809090909 = 0.01193317424
   951  	// node3 = 0.01818181818 / 0.3809090909 = 0.0477326969
   952  	// node4 = 0.02727272727 / 0.3809090909 = 0.07159904534
   953  	// node5 = 0.03636363636 / 0.3809090909 = 0.09546539379
   954  	// node6 = 0.04545454545 / 0.3809090909 = 0.1193317422
   955  	// node7 = 0.05454545455 / 0.3809090909 = 0.1431980907
   956  	// node8 = 0.06363636364 / 0.3809090909 = 0.1670644391
   957  	// node9 = 0.06545454545 / 0.3809090909 = 0.1718377088
   958  	// node10 = 0.06545454545 / 0.3809090909 = 0.1718377088
   959  	require.Equal(t, "0.00000000000", scoreData.NormalisedScores["node1"].StringFixed(11))
   960  	require.Equal(t, "0.0119331742", scoreData.NormalisedScores["node2"].StringFixed(10))
   961  	require.Equal(t, "0.0477326969", scoreData.NormalisedScores["node3"].StringFixed(10))
   962  	require.Equal(t, "0.0715990453", scoreData.NormalisedScores["node4"].StringFixed(10))
   963  	require.Equal(t, "0.0954653938", scoreData.NormalisedScores["node5"].StringFixed(10))
   964  	require.Equal(t, "0.1193317422", scoreData.NormalisedScores["node6"].StringFixed(10))
   965  	require.Equal(t, "0.1431980907", scoreData.NormalisedScores["node7"].StringFixed(10))
   966  	require.Equal(t, "0.1670644391", scoreData.NormalisedScores["node8"].StringFixed(10))
   967  	require.Equal(t, "0.1718377088", scoreData.NormalisedScores["node9"].StringFixed(10))
   968  	require.Equal(t, "0.1718377088", scoreData.NormalisedScores["node10"].StringFixed(10))
   969  
   970  	totalNormScore := num.DecimalZero()
   971  	for _, d := range scoreData.NormalisedScores {
   972  		totalNormScore = totalNormScore.Add(d)
   973  	}
   974  	require.True(t, totalNormScore.LessThanOrEqual(decimalOne))
   975  }
   976  
   977  func testGetRewardsScores(t *testing.T) {
   978  	topology := &Topology{}
   979  	topology.log = logging.NewTestLogger()
   980  	topology.validators = map[string]*valState{}
   981  	topology.validatorIncumbentBonusFactor = num.DecimalFromFloat(1.1)
   982  	topology.minimumStake = num.NewUint(3000)
   983  	topology.validatorPerformance = &MockPerformanceScore{}
   984  	topology.numberEthMultisigSigners = 7
   985  	topology.primaryMultisig = &TestMultisigTopology{
   986  		validators: map[string]struct{}{
   987  			"node1eth": {},
   988  			"node2eth": {},
   989  			"node3eth": {},
   990  			"node5eth": {},
   991  			"node7eth": {},
   992  			"node9eth": {},
   993  		},
   994  	}
   995  	topology.secondaryMultisig = &TestMultisigTopology{
   996  		validators: map[string]struct{}{
   997  			"node1eth": {},
   998  			"node2eth": {},
   999  			"node3eth": {},
  1000  			"node5eth": {},
  1001  			"node7eth": {},
  1002  			"node9eth": {},
  1003  		},
  1004  	}
  1005  
  1006  	for i := 0; i < 10; i++ {
  1007  		index := num.NewUint(uint64(i) + 1).String()
  1008  		topology.validators["node"+index] = &valState{
  1009  			data: ValidatorData{
  1010  				ID:              "node" + index,
  1011  				TmPubKey:        "key" + index,
  1012  				EthereumAddress: "node" + index + "eth",
  1013  			},
  1014  			status:           ValidatorStatusTendermint,
  1015  			heartbeatTracker: &validatorHeartbeatTracker{},
  1016  		}
  1017  	}
  1018  	for i := 10; i < 20; i++ {
  1019  		index := num.NewUint(uint64(i) + 1).String()
  1020  		topology.validators["node"+index] = &valState{
  1021  			data: ValidatorData{
  1022  				ID: "node" + index,
  1023  			},
  1024  			status:                          ValidatorStatusErsatz,
  1025  			numberOfEthereumEventsForwarded: 4,
  1026  			heartbeatTracker: &validatorHeartbeatTracker{
  1027  				blockSigs: [10]bool{},
  1028  			},
  1029  		}
  1030  		for j := 10; j < i; j++ {
  1031  			topology.validators["node"+index].heartbeatTracker.blockSigs[j-10] = true
  1032  		}
  1033  	}
  1034  	topology.rng = rand.New(rand.NewSource(100000))
  1035  	ctrl := gomock.NewController(t)
  1036  	defer ctrl.Finish()
  1037  
  1038  	broker := bmocks.NewMockBroker(ctrl)
  1039  	topology.broker = broker
  1040  
  1041  	var bEvents []events.Event
  1042  	broker.EXPECT().SendBatch(gomock.Any()).Do(func(evnts []events.Event) { bEvents = evnts }).Times(1)
  1043  
  1044  	delegation := []*types.ValidatorData{
  1045  		{NodeID: "node1", PubKey: "node1PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key1"},
  1046  		{NodeID: "node2", PubKey: "node2PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key2"},
  1047  		{NodeID: "node3", PubKey: "node3PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key3"},
  1048  		{NodeID: "node4", PubKey: "node4PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key4"},
  1049  		{NodeID: "node5", PubKey: "node5PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key5"},
  1050  		{NodeID: "node6", PubKey: "node6PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key6"},
  1051  		{NodeID: "node7", PubKey: "node7PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(6000), Delegators: map[string]*num.Uint{}, TmPubKey: "key7"},
  1052  		{NodeID: "node8", PubKey: "node8PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(5000), Delegators: map[string]*num.Uint{}, TmPubKey: "key8"},
  1053  		{NodeID: "node9", PubKey: "node9PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(4000), Delegators: map[string]*num.Uint{}, TmPubKey: "key9"},
  1054  		{NodeID: "node10", PubKey: "node10PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key10"},
  1055  		{NodeID: "node11", PubKey: "node11PubKey", StakeByDelegators: num.NewUint(8000), SelfStake: num.NewUint(2000), Delegators: map[string]*num.Uint{}, TmPubKey: "key11"},
  1056  		{NodeID: "node12", PubKey: "node12PubKey", StakeByDelegators: num.NewUint(2000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key12"},
  1057  		{NodeID: "node13", PubKey: "node13PubKey", StakeByDelegators: num.NewUint(3000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key13"},
  1058  		{NodeID: "node14", PubKey: "node14PubKey", StakeByDelegators: num.NewUint(4000), SelfStake: num.NewUint(11000), Delegators: map[string]*num.Uint{}, TmPubKey: "key14"},
  1059  		{NodeID: "node15", PubKey: "node15PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(15000), Delegators: map[string]*num.Uint{}, TmPubKey: "key15"},
  1060  		{NodeID: "node16", PubKey: "node16PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(7000), Delegators: map[string]*num.Uint{}, TmPubKey: "key16"},
  1061  		{NodeID: "node17", PubKey: "node17PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(6000), Delegators: map[string]*num.Uint{}, TmPubKey: "key17"},
  1062  		{NodeID: "node18", PubKey: "node18PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(5000), Delegators: map[string]*num.Uint{}, TmPubKey: "key18"},
  1063  		{NodeID: "node19", PubKey: "node19PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(4000), Delegators: map[string]*num.Uint{}, TmPubKey: "key19"},
  1064  		{NodeID: "node20", PubKey: "node20PubKey", StakeByDelegators: num.NewUint(5000), SelfStake: num.NewUint(3000), Delegators: map[string]*num.Uint{}, TmPubKey: "key20"},
  1065  	}
  1066  
  1067  	tmScores, ezScores := topology.GetRewardsScores(context.Background(), "1", delegation, types.StakeScoreParams{MinVal: num.DecimalFromFloat(5), CompLevel: num.DecimalFromFloat(3.3), OptimalStakeMultiplier: num.DecimalFromFloat(5)})
  1068  
  1069  	// tendermint
  1070  	require.Equal(t, "0.00000000000", tmScores.NormalisedScores["node1"].StringFixed(11))
  1071  	require.Equal(t, "0.08230452675", tmScores.NormalisedScores["node2"].StringFixed(11))
  1072  	require.Equal(t, "0.16460905350", tmScores.NormalisedScores["node3"].StringFixed(11))
  1073  	require.Equal(t, "0.00000000000", tmScores.NormalisedScores["node4"].StringFixed(11))
  1074  	require.Equal(t, "0.32921810700", tmScores.NormalisedScores["node5"].StringFixed(11))
  1075  	require.Equal(t, "0.07407407407", tmScores.NormalisedScores["node6"].StringFixed(11))
  1076  	require.Equal(t, "0.15843621399", tmScores.NormalisedScores["node7"].StringFixed(11))
  1077  	require.Equal(t, "0.06172839506", tmScores.NormalisedScores["node8"].StringFixed(11))
  1078  	require.Equal(t, "0.13", tmScores.NormalisedScores["node9"].StringFixed(2))
  1079  	require.Equal(t, "0.00000000000", tmScores.NormalisedScores["node10"].StringFixed(11))
  1080  
  1081  	// ersatz
  1082  	require.Equal(t, "0.00000000000", ezScores.NormalisedScores["node11"].StringFixed(11))
  1083  	require.Equal(t, "0.01020408163", ezScores.NormalisedScores["node12"].StringFixed(11))
  1084  	require.Equal(t, "0.04081632653", ezScores.NormalisedScores["node13"].StringFixed(11))
  1085  	require.Equal(t, "0.09183673469", ezScores.NormalisedScores["node14"].StringFixed(11))
  1086  	require.Equal(t, "0.1632653061", ezScores.NormalisedScores["node15"].StringFixed(10))
  1087  	require.Equal(t, "0.1224489796", ezScores.NormalisedScores["node16"].StringFixed(10))
  1088  	require.Equal(t, "0.1346938776", ezScores.NormalisedScores["node17"].StringFixed(10))
  1089  	require.Equal(t, "0.1428571429", ezScores.NormalisedScores["node18"].StringFixed(10))
  1090  	require.Equal(t, "0.1469387755", ezScores.NormalisedScores["node19"].StringFixed(10))
  1091  	require.Equal(t, "0.1469387755", ezScores.NormalisedScores["node20"].StringFixed(10))
  1092  
  1093  	require.Equal(t, 20, len(bEvents))
  1094  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node1", "1", num.DecimalZero(), num.DecimalZero(), num.MustDecimalFromString("0.0909090909090909"), num.DecimalZero(), num.DecimalFromFloat(1), "tendermint"), bEvents[0].(*events.ValidatorScore))
  1095  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node10", "1", num.DecimalZero(), num.DecimalZero(), num.MustDecimalFromString("0.0727272727272727"), num.DecimalFromFloat(1), num.DecimalZero(), "tendermint"), bEvents[1].(*events.ValidatorScore))
  1096  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node2", "1", num.MustDecimalFromString("0.0363636363636364"), num.MustDecimalFromString("0.0823045267489713"), num.MustDecimalFromString("0.0454545454545455"), num.DecimalFromFloat(0.8), num.DecimalFromFloat(1), "tendermint"), bEvents[2].(*events.ValidatorScore))
  1097  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node3", "1", num.MustDecimalFromString("0.07272727272727272"), num.MustDecimalFromString("0.1646090534979424"), num.MustDecimalFromString("0.0909090909090909"), num.DecimalFromFloat(0.8), num.DecimalFromFloat(1), "tendermint"), bEvents[3].(*events.ValidatorScore))
  1098  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node4", "1", num.DecimalZero(), num.DecimalZero(), num.MustDecimalFromString("0.1363636363636364"), num.DecimalFromFloat(0.8), num.DecimalFromFloat(0), "tendermint"), bEvents[4].(*events.ValidatorScore))
  1099  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node5", "1", num.MustDecimalFromString("0.14545454545454544"), num.MustDecimalFromString("0.3292181069958847"), num.MustDecimalFromString("0.1818181818181818"), num.DecimalFromFloat(0.8), num.DecimalFromFloat(1), "tendermint"), bEvents[5].(*events.ValidatorScore))
  1100  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node6", "1", num.MustDecimalFromString("0.03272727272727273"), num.MustDecimalFromString("0.0740740740740741"), num.MustDecimalFromString("0.1090909090909091"), num.DecimalFromFloat(0.3), num.DecimalFromFloat(1), "tendermint"), bEvents[6].(*events.ValidatorScore))
  1101  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node7", "1", num.MustDecimalFromString("0.07"), num.MustDecimalFromString("0.1584362139917695"), num.MustDecimalFromString("0.1"), num.DecimalFromFloat(0.7), num.DecimalFromFloat(1), "tendermint"), bEvents[7].(*events.ValidatorScore))
  1102  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node8", "1", num.MustDecimalFromString("0.02727272727272727"), num.MustDecimalFromString("0.0617283950617284"), num.MustDecimalFromString("0.0909090909090909"), num.DecimalFromFloat(0.3), num.DecimalFromFloat(1), "tendermint"), bEvents[8].(*events.ValidatorScore))
  1103  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node9", "1", num.MustDecimalFromString("0.05727272727272726"), num.MustDecimalFromString("0.1296296296296296"), num.MustDecimalFromString("0.0818181818181818"), num.DecimalFromFloat(0.7), num.DecimalFromFloat(1), "tendermint"), bEvents[9].(*events.ValidatorScore))
  1104  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node11", "1", num.DecimalZero(), num.DecimalZero(), num.MustDecimalFromString("0.0909090909090909"), num.DecimalZero(), num.DecimalFromFloat(1), "ersatz"), bEvents[10].(*events.ValidatorScore))
  1105  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node12", "1", num.MustDecimalFromString("0.00454545454545455"), num.MustDecimalFromString("0.0102040816326531"), num.MustDecimalFromString("0.0454545454545455"), num.DecimalFromFloat(0.1), num.DecimalFromFloat(1), "ersatz"), bEvents[11].(*events.ValidatorScore))
  1106  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node13", "1", num.MustDecimalFromString("0.01818181818181818"), num.MustDecimalFromString("0.0408163265306122"), num.MustDecimalFromString("0.0909090909090909"), num.DecimalFromFloat(0.2), num.DecimalFromFloat(1), "ersatz"), bEvents[12].(*events.ValidatorScore))
  1107  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node14", "1", num.MustDecimalFromString("0.04090909090909092"), num.MustDecimalFromString("0.0918367346938776"), num.MustDecimalFromString("0.1363636363636364"), num.DecimalFromFloat(0.3), num.DecimalFromFloat(1), "ersatz"), bEvents[13].(*events.ValidatorScore))
  1108  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node15", "1", num.MustDecimalFromString("0.07272727272727272"), num.MustDecimalFromString("0.163265306122449"), num.MustDecimalFromString("0.1818181818181818"), num.DecimalFromFloat(0.4), num.DecimalFromFloat(1), "ersatz"), bEvents[14].(*events.ValidatorScore))
  1109  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node16", "1", num.MustDecimalFromString("0.05454545454545455"), num.MustDecimalFromString("0.1224489795918368"), num.MustDecimalFromString("0.1090909090909091"), num.DecimalFromFloat(0.5), num.DecimalFromFloat(1), "ersatz"), bEvents[15].(*events.ValidatorScore))
  1110  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node17", "1", num.MustDecimalFromString("0.06"), num.MustDecimalFromString("0.1346938775510204"), num.MustDecimalFromString("0.1"), num.DecimalFromFloat(0.6), num.DecimalFromFloat(1), "ersatz"), bEvents[16].(*events.ValidatorScore))
  1111  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node18", "1", num.MustDecimalFromString("0.06363636363636363"), num.MustDecimalFromString("0.1428571428571429"), num.MustDecimalFromString("0.0909090909090909"), num.DecimalFromFloat(0.7), num.DecimalFromFloat(1), "ersatz"), bEvents[17].(*events.ValidatorScore))
  1112  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node19", "1", num.MustDecimalFromString("0.06545454545454544"), num.MustDecimalFromString("0.1469387755102041"), num.MustDecimalFromString("0.0818181818181818"), num.DecimalFromFloat(0.8), num.DecimalFromFloat(1), "ersatz"), bEvents[18].(*events.ValidatorScore))
  1113  	verifyEvent(t, events.NewValidatorScore(context.Background(), "node20", "1", num.MustDecimalFromString("0.06545454545454543"), num.MustDecimalFromString("0.1469387755102039"), num.MustDecimalFromString("0.0727272727272727"), num.DecimalFromFloat(0.9), num.DecimalFromFloat(1), "ersatz"), bEvents[19].(*events.ValidatorScore))
  1114  }
  1115  
  1116  func verifyEvent(t *testing.T, expected, actual *events.ValidatorScore) {
  1117  	t.Helper()
  1118  	require.Equal(t, expected.EpochSeq, actual.EpochSeq)
  1119  	require.Equal(t, expected.ValidatorScore, actual.ValidatorScore)
  1120  	require.Equal(t, expected.MultisigScore, actual.MultisigScore)
  1121  	require.Equal(t, expected.NodeID, actual.NodeID)
  1122  	require.Equal(t, expected.NormalisedScore, actual.NormalisedScore)
  1123  	require.Equal(t, expected.RawValidatorScore, actual.RawValidatorScore)
  1124  	require.Equal(t, expected.ValidatorPerformance, actual.ValidatorPerformance)
  1125  	require.Equal(t, expected.ValidatorStatus, actual.ValidatorStatus)
  1126  }
  1127  
  1128  func TestAddressMapping(t *testing.T) {
  1129  	tmKey := "7kRL1jCJH8QUDTHK90/Nz9lIAvl8/s1Z70XL1EXFkaM="
  1130  	require.Equal(t, "13fa0b679d6064772567c7a6050b42cca1c7c8cd", tmPubKeyToAddress(tmKey))
  1131  }
  1132  
  1133  type MockPerformanceScore struct{}
  1134  
  1135  func (*MockPerformanceScore) ValidatorPerformanceScore(tmPubKey string, power, totalPower int64, scalingFactor num.Decimal) num.Decimal {
  1136  	if tmPubKey == "key6" || tmPubKey == "key8" {
  1137  		return num.DecimalFromFloat(0.3)
  1138  	}
  1139  	if tmPubKey == "key7" || tmPubKey == "key9" {
  1140  		return num.DecimalFromFloat(0.7)
  1141  	}
  1142  	if tmPubKey == "key10" {
  1143  		return num.DecimalFromFloat(1)
  1144  	}
  1145  	return num.DecimalFromFloat(0.8)
  1146  }
  1147  
  1148  func (*MockPerformanceScore) BeginBlock(ctx context.Context, proposer string) {
  1149  }
  1150  
  1151  func (*MockPerformanceScore) Serialize() *v1.ValidatorPerformance {
  1152  	return nil
  1153  }
  1154  func (*MockPerformanceScore) Deserialize(*v1.ValidatorPerformance) {}
  1155  
  1156  func (*MockPerformanceScore) Reset() {}