github.com/nnlgsakib/mind-dpos@v0.0.0-20230606105614-f3c8ca06f808/consensus/alien/signer_queue_test.go (about)

     1  // Copyright 2018 The gttc Authors
     2  // This file is part of the gttc library.
     3  //
     4  // The gttc 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 gttc 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 gttc library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package alien implements the delegated-proof-of-stake consensus engine.
    18  
    19  package alien
    20  
    21  import (
    22  	"bytes"
    23  	"math/big"
    24  	"testing"
    25  
    26  	"github.com/TTCECO/gttc/common"
    27  	"github.com/TTCECO/gttc/params"
    28  )
    29  
    30  // Tests that voting is evaluated correctly for various simple and complex scenarios.
    31  func TestQueue(t *testing.T) {
    32  	// Define the various voting scenarios to test
    33  	tests := []struct {
    34  		addrNames      []string // accounts used in this case
    35  		signers        []string
    36  		number         uint64
    37  		maxSignerCount uint64
    38  		historyHash    []string
    39  		tally          map[string]uint64
    40  		punished       map[string]uint64
    41  		result         []string // the result of current snapshot
    42  	}{
    43  		{
    44  			/* 	Case 0:
    45  			*   new loop signer queue is create at blocknumber 2,
    46  			*   the new signerQueue is selected by tally, and random order depends on history hash
    47  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> A, B, C
    48  			*   step 2: the top 3 signer is map to historyHash A->c, B->b, C->a
    49  			*   step 3: the result order is set by historyHash decrease -> A, B, C
    50  			 */
    51  			addrNames:      []string{"A", "B", "C", "D"},
    52  			signers:        []string{"A", "B", "C", "D"},
    53  			number:         2,
    54  			maxSignerCount: 3,
    55  			historyHash:    []string{"a", "b", "c"},
    56  			tally:          map[string]uint64{"D": 5, "A": 30, "B": 20, "C": 10},
    57  			punished:       map[string]uint64{},
    58  			result:         []string{"A", "B", "C"},
    59  		},
    60  		{
    61  			/* 	Case 1:
    62  			*   follow test case 0. the tally is same but history hash is x,b,c
    63  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> A, B, C
    64  			*   step 2: the top 3 signer is map to historyHash A->c, B->b, C->x
    65  			*   step 3: the result order is set by historyHash decrease -> C, A, B
    66  			*
    67  			 */
    68  			addrNames:      []string{"A", "B", "C"},
    69  			signers:        []string{"A", "B", "C"},
    70  			number:         2,
    71  			maxSignerCount: 3,
    72  			historyHash:    []string{"x", "b", "c"},
    73  			tally:          map[string]uint64{"A": 30, "B": 20, "C": 10},
    74  			punished:       map[string]uint64{},
    75  			result:         []string{"C", "A", "B"},
    76  		},
    77  		{
    78  			/* 	Case 2:
    79  			*   fllow test case 0. the tally is same but history hash is a,x,c
    80  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> A, B, C
    81  			*   step 2: the top 3 signer is map to historyHash A->c, B->x, C->a
    82  			*   step 3: the result order is set by historyHash decrease -> B, A, C
    83  			*
    84  			 */
    85  			addrNames:      []string{"A", "B", "C"},
    86  			signers:        []string{"A", "B", "C"},
    87  			number:         2,
    88  			maxSignerCount: 3,
    89  			historyHash:    []string{"a", "x", "c"},
    90  			tally:          map[string]uint64{"A": 30, "B": 20, "C": 10},
    91  			punished:       map[string]uint64{},
    92  			result:         []string{"B", "A", "C"},
    93  		},
    94  		{
    95  			/* 	Case 3:
    96  			*   fllow test case 0. the tally is changed and history hash is a,b,c
    97  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> B, A, C
    98  			*   step 2: the top 3 signer is map to historyHash B->c, A->b, C->a
    99  			*   step 3: the result order is set by historyHash decrease -> B, A, C
   100  			*
   101  			 */
   102  			addrNames:      []string{"A", "B", "C"},
   103  			signers:        []string{"A", "B", "C"},
   104  			number:         2,
   105  			maxSignerCount: 3,
   106  			historyHash:    []string{"a", "b", "c"},
   107  			tally:          map[string]uint64{"A": 30, "B": 40, "C": 10},
   108  			punished:       map[string]uint64{},
   109  			result:         []string{"B", "A", "C"},
   110  		},
   111  		{
   112  			/* 	Case 4:
   113  			*   fllow test case 0. the tally is changed and history hash is x,b,c
   114  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> B, A, C
   115  			*   step 2: the top 3 signer is map to historyHash B->c, A->b, C->x
   116  			*   step 3: the result order is set by historyHash decrease -> C, B, A
   117  			*
   118  			 */
   119  			addrNames:      []string{"A", "B", "C"},
   120  			signers:        []string{"A", "B", "C"},
   121  			number:         2,
   122  			maxSignerCount: 3,
   123  			historyHash:    []string{"x", "b", "c"},
   124  			tally:          map[string]uint64{"A": 30, "B": 40, "C": 10},
   125  			punished:       map[string]uint64{},
   126  			result:         []string{"C", "B", "A"},
   127  		},
   128  		{
   129  			/* 	Case 5:
   130  			*   fllow test case 0. the tally is changed and history hash is a,b,c
   131  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> but same t ally
   132  			*   step 2: order by address (NOT A, B, C , address is [20]byte) desc, different by each test.
   133  			*   step 3: the top 3 signer is map to historyHash
   134  			*   step 4: the result order is set by historyHash decrease
   135  			*   The result will be checked if order by address desc if result if empty
   136  			 */
   137  			addrNames:      []string{"A", "B", "C"},
   138  			signers:        []string{"A", "B", "C"},
   139  			number:         2,
   140  			maxSignerCount: 3,
   141  			historyHash:    []string{"a", "b", "c"},
   142  			tally:          map[string]uint64{"A": 30, "B": 30, "C": 30},
   143  			punished:       map[string]uint64{},
   144  			result:         []string{}, // If tally(punished include) is same, then result order by their address
   145  		},
   146  		{
   147  			/* 	Case 6:
   148  			*   fllow test case 0. the tally is changed and history hash is x,b,c
   149  			*   step 1: the top 3(maxSignerCount) is selected order by tally -> same tally
   150  			*   step 2: consider the punished for each account, result order -> A, B, C
   151  			*   step 3: the top 3 signer is map to historyHash A->c, B->b, C->x
   152  			*   step 4: the result order is set by historyHash decrease -> C, A, B
   153  			*
   154  			 */
   155  			addrNames:      []string{"A", "B", "C"},
   156  			signers:        []string{"A", "B", "C"},
   157  			number:         2,
   158  			maxSignerCount: 3,
   159  			historyHash:    []string{"x", "b", "c"},
   160  			tally:          map[string]uint64{"A": 300, "B": 300, "C": 300},
   161  			punished:       map[string]uint64{"A": 500, "B": 600, "C": 800},
   162  			result:         []string{"C", "A", "B"},
   163  		},
   164  	}
   165  
   166  	// Run through the scenarios and test them
   167  	for i, tt := range tests {
   168  		candidateNeedPD = false
   169  		// Create the account pool and generate the initial set of all address in addrNames
   170  		accounts := newTesterAccountPool()
   171  		addrNames := make([]common.Address, len(tt.addrNames))
   172  		for j, signer := range tt.addrNames {
   173  			addrNames[j] = accounts.address(signer)
   174  		}
   175  		for j := 0; j < len(addrNames); j++ {
   176  			for k := j + 1; k < len(addrNames); k++ {
   177  				if bytes.Compare(addrNames[j][:], addrNames[k][:]) > 0 {
   178  					addrNames[j], addrNames[k] = addrNames[k], addrNames[j]
   179  				}
   180  			}
   181  		}
   182  
   183  		snap := &Snapshot{
   184  			config:   &params.AlienConfig{MaxSignerCount: tt.maxSignerCount},
   185  			Number:   tt.number,
   186  			LCRS:     1,
   187  			Tally:    make(map[common.Address]*big.Int),
   188  			Punished: make(map[common.Address]uint64),
   189  		}
   190  
   191  		snap.Hash.SetString(tt.historyHash[len(tt.historyHash)-1])
   192  		for _, hash := range tt.historyHash {
   193  			var hh common.Hash
   194  			hh.SetString(hash)
   195  			snap.HistoryHash = append(snap.HistoryHash, hh)
   196  		}
   197  
   198  		for signer, tally := range tt.tally {
   199  			snap.Tally[accounts.address(signer)] = big.NewInt(int64(tally))
   200  		}
   201  
   202  		for signer, punish := range tt.punished {
   203  			snap.Punished[accounts.address(signer)] = punish
   204  		}
   205  
   206  		signerQueue, err := snap.createSignerQueue()
   207  		if err != nil {
   208  			t.Errorf("test %d: create signer queue fail , err = %s", i, err)
   209  			continue
   210  		}
   211  		if len(tt.result) == 0 {
   212  			for j, signer := range signerQueue {
   213  				if j >= 1 && signerQueue[j-1].Str() < signerQueue[j].Str() {
   214  					t.Errorf("test %d: result is not correct, signerQueue(%d) %s larger than signerQueue(%d) %s ", i, j, signer.Hex(), j-1, signerQueue[j-1].Hex())
   215  				}
   216  			}
   217  		} else {
   218  			if len(signerQueue) != len(tt.result) {
   219  				t.Errorf("test %d: length of result is not correct. len(signerQueue) is %d, but len(tt.result) is %d", i, len(signerQueue), len(tt.result))
   220  				continue
   221  			}
   222  			for j, signer := range signerQueue {
   223  				if signer.Hex() != accounts.address(tt.result[j]).Hex() {
   224  					t.Errorf("test %d: result is not correct signerQueue(%d) is %s, but result(%d) is %s", i, j, signer.Hex(), j, accounts.address(tt.result[j]).Hex())
   225  				}
   226  			}
   227  		}
   228  
   229  	}
   230  }