github.com/aergoio/aergo@v1.3.1/consensus/impl/dpos/lib_test.go (about)

     1  package dpos
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/aergoio/aergo/internal/enc"
     8  	"github.com/aergoio/aergo/types"
     9  	"github.com/libp2p/go-libp2p-core/crypto"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  type testChain struct {
    14  	chain  []*types.Block
    15  	status *Status
    16  	bestNo types.BlockNo
    17  
    18  	bpid          string
    19  	lpb           map[string]types.BlockNo
    20  	bpKey         []crypto.PrivKey
    21  	bpClusterSize uint16
    22  }
    23  
    24  type testCluster struct {
    25  	size uint16
    26  }
    27  
    28  func (c *testCluster) Size() uint16 {
    29  	return c.size
    30  }
    31  
    32  func (c *testCluster) Update(ids []string) error {
    33  	return nil
    34  }
    35  
    36  func newTestChain(clusterSize uint16) (*testChain, error) {
    37  	bpKey := make([]crypto.PrivKey, int(clusterSize))
    38  	for i := 0; i < int(clusterSize); i++ {
    39  		var err error
    40  		bpKey[i], _, err = crypto.GenerateKeyPair(crypto.Secp256k1, 256)
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  	}
    45  
    46  	b, err := bpKey[0].GetPublic().Bytes()
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	tc := &testChain{
    52  		chain:         make([]*types.Block, 0),
    53  		status:        NewStatus(&testCluster{size: clusterSize}, nil, nil, 0),
    54  		bpid:          enc.ToString(b),
    55  		lpb:           make(map[string]types.BlockNo),
    56  		bpKey:         bpKey,
    57  		bpClusterSize: clusterSize,
    58  	}
    59  	tc.setGenesis(types.NewBlock(nil, nil, nil, nil, nil, 0))
    60  
    61  	// Prevent DB access
    62  	tc.status.done = true
    63  
    64  	return tc, nil
    65  }
    66  
    67  func (tc *testChain) setGenesis(block *types.Block) {
    68  	if block.BlockNo() != 0 {
    69  		panic("invalid genesis block: non-zero block no")
    70  	}
    71  	tc.status.libState.genesisInfo = &blockInfo{BlockHash: block.ID(), BlockNo: 0}
    72  	tc.status.bestBlock = block
    73  	tc.chain = append(tc.chain, block)
    74  }
    75  
    76  func (tc *testChain) addBlock(i types.BlockNo) error {
    77  	pk := tc.getBpKey(i % types.BlockNo(tc.bpClusterSize))
    78  	b, err := pk.Bytes()
    79  	if err != nil {
    80  		return err
    81  	}
    82  	spk := enc.ToString(b)
    83  
    84  	prevBlock := tc.chain[len(tc.chain)-1]
    85  	block := types.NewBlock(prevBlock, nil, nil, nil, nil, 0)
    86  
    87  	confirmNo := func(no types.BlockNo) (confirms types.BlockNo) {
    88  		lpb := types.BlockNo(0)
    89  		if v, exist := tc.lpb[spk]; exist {
    90  			lpb = v
    91  		}
    92  		confirms = no - lpb
    93  
    94  		return
    95  	}
    96  	block.SetConfirms(confirmNo(block.BlockNo()))
    97  
    98  	if err = block.Sign(pk); err != nil {
    99  		return err
   100  	}
   101  
   102  	tc.lpb[spk] = block.BlockNo()
   103  
   104  	tc.chain = append(tc.chain, block)
   105  	tc.bestNo = types.BlockNo(len(tc.chain) - 1)
   106  	tc.status.Update(block)
   107  
   108  	return nil
   109  }
   110  
   111  func (tc *testChain) getBpKey(i types.BlockNo) crypto.PrivKey {
   112  	return tc.bpKey[i%types.BlockNo(tc.bpClusterSize)]
   113  }
   114  
   115  func TestTestChain(t *testing.T) {
   116  	const (
   117  		clusterSize = 3
   118  		maxBlockNo  = types.BlockNo(clusterSize) * 20
   119  	)
   120  
   121  	a := assert.New(t)
   122  	tc, err := newTestChain(clusterSize)
   123  	a.Nil(err)
   124  
   125  	for i := types.BlockNo(1); i <= maxBlockNo; i++ {
   126  		a.Nil(tc.addBlock(i))
   127  		fmt.Println("LIB:", tc.status.libState.Lib.BlockNo)
   128  	}
   129  
   130  	a.Equal(tc.bestNo, maxBlockNo)
   131  	a.Equal(tc.status.libState.Lib.BlockNo, maxBlockNo-clusterSize-1)
   132  }
   133  
   134  func TestNumLimitGC(t *testing.T) {
   135  	const (
   136  		clusterSize    = 23
   137  		consensusCount = clusterSize*2/3 + 1
   138  	)
   139  
   140  	a := assert.New(t)
   141  
   142  	ls := newLibStatus(consensusCount)
   143  
   144  	for i := 1; i <= clusterSize*3; i++ {
   145  		ls.confirms.PushBack(
   146  			&confirmInfo{
   147  				blockInfo: &blockInfo{BlockNo: types.BlockNo(i)},
   148  			})
   149  	}
   150  
   151  	ls.gc()
   152  	a.True(ls.confirms.Len() <= ls.gcNumLimit())
   153  }
   154  
   155  func TestLibGC(t *testing.T) {
   156  	const (
   157  		clusterSize    = 23
   158  		consensusCount = clusterSize*2/3 + 1
   159  		libNo          = 3
   160  	)
   161  
   162  	a := assert.New(t)
   163  
   164  	ls := newLibStatus(consensusCount)
   165  	ls.Lib = &blockInfo{BlockNo: libNo}
   166  
   167  	for i := 1; i <= clusterSize*3; i++ {
   168  		ls.confirms.PushBack(
   169  			&confirmInfo{
   170  				blockInfo: &blockInfo{BlockNo: types.BlockNo(i)},
   171  			})
   172  	}
   173  
   174  	ls.gc()
   175  	a.True(cInfo(ls.confirms.Front()).blockInfo.BlockNo > libNo)
   176  }