github.com/klaytn/klaytn@v1.12.1/reward/staking_info_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package reward
    18  
    19  import (
    20  	"encoding/json"
    21  	"math"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/klaytn/klaytn/common"
    26  	"github.com/klaytn/klaytn/params"
    27  	"github.com/klaytn/klaytn/storage/database"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  type stakingInfoTestCase struct {
    33  	stakingInfo          *StakingInfo
    34  	expectedConsolidated *ConsolidatedStakingInfo
    35  	expectedAmounts      map[common.Address]uint64
    36  }
    37  
    38  var stakingInfoTestCases = generateStakingInfoTestCases()
    39  
    40  func generateStakingInfoTestCases() []stakingInfoTestCase {
    41  	var (
    42  		n1 = common.HexToAddress("0x8aD8F547fa00f58A8c4fb3B671Ee5f1A75bA028a")
    43  		n2 = common.HexToAddress("0xB2AAda7943919e82143324296987f6091F3FDC9e")
    44  		n3 = common.HexToAddress("0xD95c70710f07A3DaF7ae11cFBa10c789da3564D0")
    45  		n4 = common.HexToAddress("0xC704765db1d21C2Ea6F7359dcB8FD5233DeD16b5")
    46  
    47  		s1 = common.HexToAddress("0x4dd324F9821485caE941640B32c3Bcf1fA6E93E6")
    48  		s2 = common.HexToAddress("0x0d5Df5086B5f86f748dFaed5779c3f862C075B1f")
    49  		s3 = common.HexToAddress("0xD3Ff05f00491571E86A3cc8b0c320aA76D7413A5")
    50  		s4 = common.HexToAddress("0x11EF8e61d10365c2ECAe0E95b5fFa9ed4D68d64f")
    51  
    52  		r1 = common.HexToAddress("0x241c793A9AD555f52f6C3a83afe6178408796ab2")
    53  		r2 = common.HexToAddress("0x79b427Fb77077A9716E08D049B0e8f36Abfc8E2E")
    54  		r3 = common.HexToAddress("0x62E47d858bf8513fc401886B94E33e7DCec2Bfb7")
    55  		r4 = common.HexToAddress("0xf275f9f4c0d375F9E3E50370f93b504A1e45dB09")
    56  
    57  		kcf = common.HexToAddress("0x136807B12327a8AfF9831F09617dA1B9D398cda2")
    58  		kff = common.HexToAddress("0x46bA8F7538CD0749e572b2631F9FB4Ce3653AFB8")
    59  
    60  		a0 uint64 = 0
    61  		aL uint64 = 1000000  // less than minstaking
    62  		aM uint64 = 2000000  // exactly minstaking (params.DefaultMinimumStake)
    63  		a1 uint64 = 10000000 // above minstaking. Using 1,2,4,8 to uniquely spot errors
    64  		a2 uint64 = 20000000
    65  		a3 uint64 = 40000000
    66  		a4 uint64 = 80000000
    67  	)
    68  	if aM != params.DefaultMinimumStake.Uint64() {
    69  		panic("broken test assumption")
    70  	}
    71  
    72  	return []stakingInfoTestCase{
    73  		// Empty
    74  		{
    75  			stakingInfo: newEmptyStakingInfo(0),
    76  			expectedConsolidated: &ConsolidatedStakingInfo{
    77  				nodes:     make([]consolidatedNode, 0),
    78  				nodeIndex: make(map[common.Address]int),
    79  			},
    80  			expectedAmounts: make(map[common.Address]uint64),
    81  		},
    82  
    83  		// 1 entry
    84  		{
    85  			stakingInfo: &StakingInfo{
    86  				BlockNum:              86400,
    87  				CouncilNodeAddrs:      []common.Address{n1},
    88  				CouncilStakingAddrs:   []common.Address{s1},
    89  				CouncilRewardAddrs:    []common.Address{r1},
    90  				KCFAddr:               kcf,
    91  				KFFAddr:               kff,
    92  				UseGini:               true,
    93  				Gini:                  0.00,
    94  				CouncilStakingAmounts: []uint64{a1},
    95  			},
    96  			expectedConsolidated: &ConsolidatedStakingInfo{
    97  				nodes: []consolidatedNode{
    98  					{[]common.Address{n1}, []common.Address{s1}, r1, a1},
    99  				},
   100  				nodeIndex: map[common.Address]int{n1: 0},
   101  			},
   102  			expectedAmounts: map[common.Address]uint64{n1: a1},
   103  		},
   104  
   105  		// Ordinary 4-entry info
   106  		{
   107  			stakingInfo: &StakingInfo{
   108  				BlockNum:              2 * 86400,
   109  				CouncilNodeAddrs:      []common.Address{n1, n2, n3, n4},
   110  				CouncilStakingAddrs:   []common.Address{s1, s2, s3, s4},
   111  				CouncilRewardAddrs:    []common.Address{r1, r2, r3, r4},
   112  				KCFAddr:               kcf,
   113  				KFFAddr:               kff,
   114  				UseGini:               true,
   115  				Gini:                  0.38, // Gini(10, 20, 40, 80)
   116  				CouncilStakingAmounts: []uint64{a1, a2, a3, a4},
   117  			},
   118  			expectedConsolidated: &ConsolidatedStakingInfo{
   119  				nodes: []consolidatedNode{
   120  					{[]common.Address{n1}, []common.Address{s1}, r1, a1},
   121  					{[]common.Address{n2}, []common.Address{s2}, r2, a2},
   122  					{[]common.Address{n3}, []common.Address{s3}, r3, a3},
   123  					{[]common.Address{n4}, []common.Address{s4}, r4, a4},
   124  				},
   125  				nodeIndex: map[common.Address]int{n1: 0, n2: 1, n3: 2, n4: 3},
   126  			},
   127  			expectedAmounts: map[common.Address]uint64{n1: a1, n2: a2, n3: a3, n4: a4},
   128  		},
   129  
   130  		// 4-entry with common reward addrs
   131  		{
   132  			stakingInfo: &StakingInfo{
   133  				BlockNum:              3 * 86400,
   134  				CouncilNodeAddrs:      []common.Address{n1, n2, n3, n4},
   135  				CouncilStakingAddrs:   []common.Address{s1, s2, s3, s4},
   136  				CouncilRewardAddrs:    []common.Address{r1, r2, r1, r2}, // r1 and r2 used twice each
   137  				KCFAddr:               kcf,
   138  				KFFAddr:               kff,
   139  				UseGini:               true,
   140  				Gini:                  0.17, // Gini(50, 100)
   141  				CouncilStakingAmounts: []uint64{a1, a2, a3, a4},
   142  			},
   143  			expectedConsolidated: &ConsolidatedStakingInfo{
   144  				nodes: []consolidatedNode{
   145  					{[]common.Address{n1, n3}, []common.Address{s1, s3}, r1, a1 + a3}, // n1 & n3
   146  					{[]common.Address{n2, n4}, []common.Address{s2, s4}, r2, a2 + a4}, // n2 & n4
   147  				},
   148  				nodeIndex: map[common.Address]int{n1: 0, n2: 1, n3: 0, n4: 1},
   149  			},
   150  			expectedAmounts: map[common.Address]uint64{n1: a1 + a3, n2: a2 + a4, n3: a1 + a3, n4: a2 + a4},
   151  		},
   152  
   153  		// 4-entry with less-than-minstaking amounts
   154  		{
   155  			stakingInfo: &StakingInfo{
   156  				BlockNum:              4 * 86400,
   157  				CouncilNodeAddrs:      []common.Address{n1, n2, n3, n4},
   158  				CouncilStakingAddrs:   []common.Address{s1, s2, s3, s4},
   159  				CouncilRewardAddrs:    []common.Address{r1, r2, r3, r4},
   160  				KCFAddr:               kcf,
   161  				KFFAddr:               kff,
   162  				UseGini:               true,
   163  				Gini:                  0.41,                     // Gini(20, 2)
   164  				CouncilStakingAmounts: []uint64{a2, aM, aL, a0}, // aL and a0 should be ignored in Gini calculation
   165  			},
   166  			expectedConsolidated: &ConsolidatedStakingInfo{
   167  				nodes: []consolidatedNode{
   168  					{[]common.Address{n1}, []common.Address{s1}, r1, a2},
   169  					{[]common.Address{n2}, []common.Address{s2}, r2, aM},
   170  					{[]common.Address{n3}, []common.Address{s3}, r3, aL},
   171  					{[]common.Address{n4}, []common.Address{s4}, r4, a0},
   172  				},
   173  				nodeIndex: map[common.Address]int{n1: 0, n2: 1, n3: 2, n4: 3},
   174  			},
   175  			expectedAmounts: map[common.Address]uint64{n1: a2, n2: aM, n3: aL, n4: a0},
   176  		},
   177  	}
   178  }
   179  
   180  func TestStakingInfo_GetIndexByNodeAddress(t *testing.T) {
   181  	testdata := []common.Address{
   182  		common.StringToAddress("0xB55e5986b972Be438b4A91d6e8726aA50AD55EDc"),
   183  		common.StringToAddress("0xaDfc427080B4a66b5a629cd633d48C5d734572cA"),
   184  		common.StringToAddress("0x994daB8EB6f3FaE044cC0c9a0AB1A038e136b0B6"),
   185  		common.StringToAddress("0xD527822212Fded72c5fE89f46281d5355BD58235"),
   186  	}
   187  	testCases := []struct {
   188  		address common.Address
   189  		index   int
   190  		err     error
   191  	}{
   192  		{common.StringToAddress("0xB55e5986b972Be438b4A91d6e8726aA50AD55EDc"), 0, nil},
   193  		{common.StringToAddress("0xaDfc427080B4a66b5a629cd633d48C5d734572cA"), 1, nil},
   194  		{common.StringToAddress("0x994daB8EB6f3FaE044cC0c9a0AB1A038e136b0B6"), 2, nil},
   195  		{common.StringToAddress("0xD527822212Fded72c5fE89f46281d5355BD58235"), 3, nil},
   196  		{common.StringToAddress("0x027AbB8c9f952cfFf01B1707fF14E2CB5D439502"), AddrNotFoundInCouncilNodes, ErrAddrNotInStakingInfo},
   197  	}
   198  
   199  	stakingInfo := newEmptyStakingInfo(0)
   200  	stakingInfo.CouncilNodeAddrs = testdata
   201  
   202  	for i := 0; i < len(testCases); i++ {
   203  		result, err := stakingInfo.GetIndexByNodeAddress(testCases[i].address)
   204  		assert.Equal(t, testCases[i].index, result)
   205  		assert.Equal(t, testCases[i].err, err)
   206  	}
   207  }
   208  
   209  func TestStakingInfo_GetStakingAmountByNodeId(t *testing.T) {
   210  	testdata := struct {
   211  		address       []common.Address
   212  		stakingAmount []uint64
   213  	}{
   214  		[]common.Address{
   215  			common.StringToAddress("0xB55e5986b972Be438b4A91d6e8726aA50AD55EDc"),
   216  			common.StringToAddress("0xaDfc427080B4a66b5a629cd633d48C5d734572cA"),
   217  			common.StringToAddress("0x994daB8EB6f3FaE044cC0c9a0AB1A038e136b0B6"),
   218  			common.StringToAddress("0xD527822212Fded72c5fE89f46281d5355BD58235"),
   219  		},
   220  		[]uint64{
   221  			100, 200, 300, 400,
   222  		},
   223  	}
   224  	testCases := []struct {
   225  		address       common.Address
   226  		stakingAmount uint64
   227  		err           error
   228  	}{
   229  		{common.StringToAddress("0xB55e5986b972Be438b4A91d6e8726aA50AD55EDc"), 100, nil},
   230  		{common.StringToAddress("0xaDfc427080B4a66b5a629cd633d48C5d734572cA"), 200, nil},
   231  		{common.StringToAddress("0x994daB8EB6f3FaE044cC0c9a0AB1A038e136b0B6"), 300, nil},
   232  		{common.StringToAddress("0xD527822212Fded72c5fE89f46281d5355BD58235"), 400, nil},
   233  		{common.StringToAddress("0x027AbB8c9f952cfFf01B1707fF14E2CB5D439502"), 0, ErrAddrNotInStakingInfo},
   234  	}
   235  
   236  	stakingInfo := newEmptyStakingInfo(0)
   237  	stakingInfo.CouncilNodeAddrs = testdata.address
   238  	stakingInfo.CouncilStakingAmounts = testdata.stakingAmount
   239  
   240  	for i := 0; i < len(testCases); i++ {
   241  		result, err := stakingInfo.GetStakingAmountByNodeId(testCases[i].address)
   242  		assert.Equal(t, testCases[i].stakingAmount, result)
   243  		assert.Equal(t, testCases[i].err, err)
   244  	}
   245  }
   246  
   247  func TestStakingInfo_String(t *testing.T) {
   248  	// No information loss in String() -> Unmarshal() round trip
   249  	for _, testcase := range stakingInfoTestCases {
   250  		resultStr := testcase.stakingInfo.String()
   251  		t.Logf("%s", resultStr)
   252  
   253  		resultByteArr := []byte(resultStr)
   254  		resultStakingInfo := &StakingInfo{}
   255  		err := json.Unmarshal(resultByteArr, resultStakingInfo)
   256  		assert.NoError(t, err)
   257  
   258  		assert.Equal(t, testcase.stakingInfo, resultStakingInfo)
   259  	}
   260  }
   261  
   262  func TestCalcGiniCoefficient(t *testing.T) {
   263  	testCase := []struct {
   264  		testdata []float64
   265  		result   float64
   266  	}{
   267  		{[]float64{1, 1, 1}, 0.0},
   268  		{[]float64{0, 8, 0, 0, 0}, 0.8},
   269  		{[]float64{5, 4, 3, 2, 1}, 0.27},
   270  	}
   271  
   272  	for i := 0; i < len(testCase); i++ {
   273  		result := CalcGiniCoefficient(testCase[i].testdata)
   274  		assert.Equal(t, testCase[i].result, result)
   275  	}
   276  }
   277  
   278  func TestGiniReflectToExpectedCCO(t *testing.T) {
   279  	testCase := []struct {
   280  		ccoToken        []float64
   281  		beforeReflected []float64
   282  		adjustment      []float64
   283  		afterReflected  []float64
   284  	}{
   285  		{
   286  			[]float64{
   287  				66666667, 233333333, 5000000, 5000000, 5000000,
   288  				77777778, 5000000, 33333333, 20000000, 16666667,
   289  				10000000, 5000000, 5000000, 5000000, 5000000,
   290  				5000000, 5000000, 5000000, 5000000, 5000000,
   291  				5000000,
   292  			},
   293  			[]float64{13, 44, 1, 1, 1, 15, 1, 6, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
   294  			[]float64{42612, 89426, 9202, 9202, 9202, 46682, 9202, 28275, 20900, 18762, 13868, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202},
   295  			[]float64{11, 23, 2, 2, 2, 12, 2, 7, 5, 5, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
   296  		},
   297  		{
   298  			[]float64{
   299  				400000000, 233333333, 233333333, 150000000, 108333333,
   300  				83333333, 66666667, 33333333, 20000000, 16666667,
   301  				10000000, 5000000, 5000000, 5000000, 5000000,
   302  				5000000, 5000000, 5000000, 5000000, 5000000,
   303  				5000000,
   304  			},
   305  			[]float64{28, 17, 17, 11, 8, 6, 5, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
   306  			[]float64{123020, 89426, 89426, 68853, 56793, 48627, 42612, 28275, 20900, 18762, 13868, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202, 9202},
   307  			[]float64{18, 13, 13, 10, 8, 7, 6, 4, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
   308  		},
   309  	}
   310  	for i := 0; i < len(testCase); i++ {
   311  		stakingInfo := newEmptyStakingInfo(uint64(1))
   312  
   313  		weights := make([]float64, len(testCase[i].ccoToken))
   314  		tokenListToCalcGini := make([]float64, len(testCase[i].ccoToken))
   315  		totalAmount := 0.0
   316  		for j := 0; j < len(testCase[i].ccoToken); j++ {
   317  			totalAmount += float64(testCase[i].ccoToken[j])
   318  			tokenListToCalcGini[j] = testCase[i].ccoToken[j]
   319  		}
   320  
   321  		for j := 0; j < len(testCase[i].ccoToken); j++ {
   322  			weights[j] = math.Round(float64(testCase[i].ccoToken[j]) * 100 / totalAmount)
   323  			if weights[j] < 1 {
   324  				weights[j] = 1
   325  			}
   326  			if weights[j] != testCase[i].beforeReflected[j] {
   327  				t.Errorf("normal weight is incorrect. result : %v expected : %v", weights[j], testCase[i].beforeReflected[j])
   328  			}
   329  		}
   330  
   331  		stakingAmountsGiniReflected := make([]float64, len(testCase[i].ccoToken))
   332  		totalAmountGiniReflected := 0.0
   333  		stakingInfo.Gini = CalcGiniCoefficient(tokenListToCalcGini)
   334  
   335  		for j := 0; j < len(stakingAmountsGiniReflected); j++ {
   336  			stakingAmountsGiniReflected[j] = math.Round(math.Pow(float64(testCase[i].ccoToken[j]), 1.0/(1+stakingInfo.Gini)))
   337  			totalAmountGiniReflected += stakingAmountsGiniReflected[j]
   338  		}
   339  
   340  		for j := 0; j < len(testCase[i].ccoToken); j++ {
   341  			if stakingAmountsGiniReflected[j] != testCase[i].adjustment[j] {
   342  				t.Errorf("staking amount reflected gini is different. result : %v expected : %v", stakingAmountsGiniReflected[j], testCase[i].adjustment[j])
   343  			}
   344  		}
   345  
   346  		for j := 0; j < len(testCase[i].ccoToken); j++ {
   347  			stakingAmountsGiniReflected[j] = math.Round(stakingAmountsGiniReflected[j] * 100 / totalAmountGiniReflected)
   348  			if stakingAmountsGiniReflected[j] != testCase[i].afterReflected[j] {
   349  				t.Errorf("weight reflected gini is different. result : %v expected : %v", stakingAmountsGiniReflected[j], testCase[i].afterReflected[j])
   350  			}
   351  		}
   352  	}
   353  }
   354  
   355  // TestStakingInfoJSON tests marshalling and unmarshalling StakingInfo
   356  // StakingInfo is marshaled before storing to DB.
   357  func TestStakingInfoJSON(t *testing.T) {
   358  	// No information loss in json.Marshal() -> json.Unmarshal() round trip
   359  	for _, testcase := range stakingInfoTestCases {
   360  		src := testcase.stakingInfo
   361  
   362  		s, err := json.Marshal(src)
   363  		require.Nil(t, err)
   364  
   365  		dst := new(StakingInfo)
   366  		err = json.Unmarshal(s, dst)
   367  		require.Nil(t, err)
   368  
   369  		assert.Equal(t, src, dst)
   370  	}
   371  }
   372  
   373  func TestConsolidatedStakingInfo(t *testing.T) {
   374  	for _, testcase := range stakingInfoTestCases {
   375  		expected := testcase.expectedConsolidated
   376  		c := testcase.stakingInfo.GetConsolidatedStakingInfo()
   377  
   378  		// Test ConsolidatedStakingInfo
   379  		assert.Equal(t, expected.nodes, c.nodes)
   380  		assert.Equal(t, expected.nodeIndex, c.nodeIndex)
   381  
   382  		// Test CalcGiniCoefficient()
   383  		expectedGini := testcase.stakingInfo.Gini
   384  		gini := c.CalcGiniCoefficientMinStake(2000000)
   385  		assert.Equal(t, expectedGini, gini)
   386  
   387  		// Test GetConsolidatedNode()
   388  		for addr, expectedAmount := range testcase.expectedAmounts {
   389  			node := c.GetConsolidatedNode(addr)
   390  			require.NotNil(t, node)
   391  			assert.Equal(t, expectedAmount, node.StakingAmount)
   392  		}
   393  	}
   394  }
   395  
   396  // oldStakingInfo is a legacy of StakingInfo providing backward-compatibility.
   397  // Since json tags of StakingInfo were changed, a node may fail to unmarshal stored data without this.
   398  // oldStakingInfo's field names are the same with StakingInfo's names, but json tag is different.
   399  type oldStakingInfo struct {
   400  	BlockNum              uint64           `json:"BlockNum"`
   401  	CouncilNodeAddrs      []common.Address `json:"CouncilNodeAddrs"`
   402  	CouncilStakingAddrs   []common.Address `json:"CouncilStakingAddrs"`
   403  	CouncilRewardAddrs    []common.Address `json:"CouncilRewardAddrs"`
   404  	KCFAddr               common.Address   `json:"KIRAddr"` // KIRAddr -> KCFAddr from v1.10.2
   405  	KFFAddr               common.Address   `json:"PoCAddr"` // PoCAddr -> KFFAddr from v1.10.2
   406  	UseGini               bool             `json:"UseGini"`
   407  	Gini                  float64          `json:"Gini"`
   408  	CouncilStakingAmounts []uint64         `json:"CouncilStakingAmounts"`
   409  }
   410  
   411  var oldInfo = oldStakingInfo{
   412  	2880,
   413  	[]common.Address{
   414  		common.HexToAddress("0x159ae5ccda31b77475c64d88d4499c86f77b7ecc"),
   415  		common.HexToAddress("0x181deb121304b0430d99328ff1a9122df9f09d7f"),
   416  		common.HexToAddress("0x324ec8f2681cd73642cc55057970540a1f4393e0"),
   417  		common.HexToAddress("0x11191029025d3fcd21001746f949b25c6e8435cc"),
   418  	},
   419  	[]common.Address{
   420  		common.HexToAddress("0x70e051c46ea76b9af9977407bb32192319907f9e"),
   421  		common.HexToAddress("0xe4a0c3821a2711758306ed57c2f4900aa9ddbb3d"),
   422  		common.HexToAddress("0xf3ba3a33b3bf7cf2085890315b41cc788770feb3"),
   423  		common.HexToAddress("0x9285a85777d0ae7e12bee3ffd7842908b2295f45"),
   424  	},
   425  	[]common.Address{
   426  		common.HexToAddress("0xd155d4277c99fa837c54a37a40a383f71a3d082a"),
   427  		common.HexToAddress("0x2b8cc0ca62537fa5e49dce197acc8a15d3c5d4a8"),
   428  		common.HexToAddress("0x7d892f470ecde693f52588dd0cfe46c3d26b6219"),
   429  		common.HexToAddress("0xa0f7354a0cef878246820b6caa19d2bdef74a0cc"),
   430  	},
   431  	common.HexToAddress("0x673003e5f9a852d3dc85b83d16ef62d45497fb96"),
   432  	common.HexToAddress("0x576dc0c2afeb1661da3cf53a60e76dd4e32c7ab1"),
   433  	false,
   434  	-1,
   435  	[]uint64{5000000, 5000000, 5000000, 5000000},
   436  }
   437  
   438  var newInfo = StakingInfo{
   439  	oldInfo.BlockNum,
   440  	[]common.Address{
   441  		common.HexToAddress("0x70e051c46ea76b9af9977407bb32192319907f9e"),
   442  		common.HexToAddress("0xe4a0c3821a2711758306ed57c2f4900aa9ddbb3d"),
   443  		common.HexToAddress("0xf3ba3a33b3bf7cf2085890315b41cc788770feb3"),
   444  		common.HexToAddress("0x11191029025d3fcd21001746f949b25c6e8435cc"),
   445  	},
   446  	[]common.Address{
   447  		common.HexToAddress("0x7d892f470ecde693f52588dd0cfe46c3d26b6219"),
   448  		common.HexToAddress("0x2b8cc0ca62537fa5e49dce197acc8a15d3c5d4a8"),
   449  		common.HexToAddress("0xa0f7354a0cef878246820b6caa19d2bdef74a0cc"),
   450  		common.HexToAddress("0x576dc0c2afeb1661da3cf53a60e76dd4e32c7ab1"),
   451  	},
   452  	[]common.Address{
   453  		common.HexToAddress("0xd155d4277c99fa837c54a37a40a383f71a3d082a"),
   454  		common.HexToAddress("0x159ae5ccda31b77475c64d88d4499c86f77b7ecc"),
   455  		common.HexToAddress("0x181deb121304b0430d99328ff1a9122df9f09d7f"),
   456  		common.HexToAddress("0x673003e5f9a852d3dc85b83d16ef62d45497fb96"),
   457  	},
   458  	common.HexToAddress("0x324ec8f2681cd73642cc55057970540a1f4393e0"),
   459  	common.HexToAddress("0x9285a85777d0ae7e12bee3ffd7842908b2295f45"),
   460  	false,
   461  	0.3,
   462  	[]uint64{15000000, 4000000, 25000000, 35000000},
   463  }
   464  
   465  // TestGetStakingInfoFromDB tests whether the node can read oldStakingInfo and StakingInfo data or not.
   466  func TestGetStakingInfoFromDB(t *testing.T) {
   467  	oldStakingManager := GetStakingManager()
   468  	defer SetTestStakingManager(oldStakingManager)
   469  
   470  	for _, info := range []interface{}{oldInfo, newInfo} {
   471  		// reset database
   472  		SetTestStakingManagerWithDB(database.NewMemoryDBManager())
   473  
   474  		infoBytes, err := json.Marshal(info)
   475  		if err != nil {
   476  			t.Fatal(err)
   477  		}
   478  
   479  		stakingManager.stakingInfoDB.WriteStakingInfo(oldInfo.BlockNum, infoBytes)
   480  		retrievedInfo, err := getStakingInfoFromDB(oldInfo.BlockNum)
   481  		if err != nil {
   482  			t.Fatal(err)
   483  		}
   484  
   485  		vInfo := reflect.ValueOf(info)
   486  		vRetriedInfo := reflect.ValueOf(*retrievedInfo)
   487  
   488  		assert.Equal(t, vInfo.NumField(), vRetriedInfo.NumField())
   489  		for i := 0; i < vInfo.NumField(); i++ {
   490  			assert.Equal(t, vInfo.Field(i).Interface(), vRetriedInfo.Field(i).Interface())
   491  		}
   492  	}
   493  }
   494  
   495  // TestStakingInfo_MarshalJSON tests marshal/unmarshal staking info data.
   496  func TestStakingInfo_MarshalJSON(t *testing.T) {
   497  	// old marshalled data, new unmarshal method
   498  	{
   499  		oldInfoByte, err := json.Marshal(oldInfo)
   500  		if err != nil {
   501  			t.Fatal(err)
   502  		}
   503  
   504  		var unmarshalled StakingInfo
   505  		if err := json.Unmarshal(oldInfoByte, &unmarshalled); err != nil {
   506  			t.Fatal(err)
   507  		}
   508  		checkStakingInfoValues(t, oldInfo, unmarshalled)
   509  	}
   510  
   511  	// new marshalled data, old unmarshal method
   512  	{
   513  		newInfoByte, err := json.Marshal(newInfo)
   514  		if err != nil {
   515  			t.Fatal(err)
   516  		}
   517  
   518  		var unmarshalled oldStakingInfo
   519  		if err := json.Unmarshal(newInfoByte, &unmarshalled); err != nil {
   520  			t.Fatal(err)
   521  		}
   522  		checkStakingInfoValues(t, newInfo, unmarshalled)
   523  	}
   524  
   525  	// new marshalled data, new unmarshal method
   526  	{
   527  		newInfoByte, err := json.Marshal(newInfo)
   528  		if err != nil {
   529  			t.Fatal(err)
   530  		}
   531  
   532  		var unmarshalled StakingInfo
   533  		if err := json.Unmarshal(newInfoByte, &unmarshalled); err != nil {
   534  			t.Fatal(err)
   535  		}
   536  		checkStakingInfoValues(t, newInfo, unmarshalled)
   537  	}
   538  }
   539  
   540  func checkStakingInfoValues(t *testing.T, info interface{}, stakingInfo interface{}) {
   541  	vOld := reflect.ValueOf(info)
   542  	vNew := reflect.ValueOf(stakingInfo)
   543  	assert.Equal(t, vOld.NumField(), vNew.NumField())
   544  
   545  	for i := 0; i < vOld.NumField(); i++ {
   546  		field := reflect.TypeOf(info).Field(i).Name
   547  		assert.Equal(t, vOld.FieldByName(field).Interface(), vNew.FieldByName(field).Interface())
   548  	}
   549  }