From 18e04669c1d7319f3100f96643b256afccaef21f Mon Sep 17 00:00:00 2001 From: kokeshiM0chi <52264064+kokeshiM0chi@users.noreply.github.com> Date: Mon, 1 Mar 2021 11:29:36 +0900 Subject: [PATCH] test: add tests for each validator type (#189) * test: add test GenFilePV() with the addition of new privKeyType * test: add aggregate signature test --- consensus/aggregate_signature_test.go | 108 ++++++++++++++++++++++++++ consensus/common_test.go | 92 ++++++++++++++++++++-- privval/file_test.go | 20 +++++ 3 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 consensus/aggregate_signature_test.go diff --git a/consensus/aggregate_signature_test.go b/consensus/aggregate_signature_test.go new file mode 100644 index 000000000..68e16ceaf --- /dev/null +++ b/consensus/aggregate_signature_test.go @@ -0,0 +1,108 @@ +package consensus + +import ( + "crypto/ed25519" + "testing" + + "github.com/tendermint/tendermint/crypto/bls" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" +) + +func startConsensusAndMakeBlocks(t *testing.T, nPeers, nVals, nValsWithComposite int) []*State { + css, _, _, cleanup := consensusNetWithPeers( + nVals, + nPeers, + t.Name(), + newMockTickerFunc(true), + newPersistentKVStoreWithPath, + nValsWithComposite) + + defer cleanup() + logger := log.TestingLogger() + + reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nPeers) + defer stopConsensusNet(logger, reactors, eventBuses) + + // map of active validators + activeVals := make(map[string]struct{}) + for i := 0; i < nVals; i++ { + pubKey, err := css[i].privValidator.GetPubKey() + require.NoError(t, err) + activeVals[string(pubKey.Address())] = struct{}{} + } + + // wait till everyone makes block 1 + timeoutWaitGroup(t, nPeers, func(j int) { + <-blocksSubs[j].Out() + }, css) + + // wait till everyone makes block 2 + waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css) + + return css +} + +func TestAggregateSignature(t *testing.T) { + const ( + nPeers = 4 + nVals = 4 + nValsWithComposite = 0 + ) + css := startConsensusAndMakeBlocks(t, nPeers, nVals, nValsWithComposite) + for _, state := range css { + block := state.blockStore.LoadBlock(2) + + // validators are ed25519 only + for _, comsig := range block.LastCommit.Signatures { + require.EqualValues(t, ed25519.PrivateKeySize, len(comsig.Signature)) + } + require.EqualValues(t, nVals, len(block.LastCommit.Signatures)) + require.Nil(t, block.LastCommit.AggregatedSignature) + } +} + +func TestAggregateSignatureWithComposite(t *testing.T) { + const ( + nPeers = 4 + nVals = 4 + nValsWithComposite = 4 + ) + css := startConsensusAndMakeBlocks(t, nPeers, nVals, nValsWithComposite) + + for _, state := range css { + block := state.blockStore.LoadBlock(2) + // validators are composite only + for _, comsig := range block.LastCommit.Signatures { + require.Nil(t, comsig.Signature) + } + require.EqualValues(t, nVals, len(block.LastCommit.Signatures)) + require.EqualValues(t, bls.SignatureSize, len(block.LastCommit.AggregatedSignature)) + } +} + +func TestAggregateSignatureWithMix(t *testing.T) { + const ( + nPeers = 4 + nVals = 4 + nValsWithComposite = 2 + expectedCntNotNilSig = nVals - nValsWithComposite + ) + css := startConsensusAndMakeBlocks(t, nPeers, nVals, nValsWithComposite) + + for _, state := range css { + block := state.blockStore.LoadBlock(2) + // composite and ed25519 validators + cnt := 0 + for _, comsig := range block.LastCommit.Signatures { + if comsig.Signature != nil { + cnt++ + } + } + // count the unaggregated sig + require.EqualValues(t, expectedCntNotNilSig, cnt) + // count the aggregated sig + require.EqualValues(t, nValsWithComposite, len(block.LastCommit.Signatures)-cnt) + } +} diff --git a/consensus/common_test.go b/consensus/common_test.go index fe926dcb2..7582ae8c3 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -768,6 +768,28 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou } } +// nPeers = nValidators(ed25519 or composite) + nNotValidator +// (0 <= numOfComposite <= nValidators) +func consensusNetWithPeers( + nValidators, + nPeers int, + testName string, + tickerFunc func() TimeoutTicker, + appFunc func(string) abci.Application, + nValsWithComposite int, +) ([]*State, *types.GenesisDoc, *cfg.Config, cleanupFunc) { + genDoc, privVals := genesisDoc(nValidators, testMinPower, types.DefaultVoterParams(), nValsWithComposite) + + css, peer0Config, configRootDirs := createPeersAndValidators(nValidators, nPeers, testName, + genDoc, privVals, tickerFunc, appFunc) + + return css, genDoc, peer0Config, func() { + for _, dir := range configRootDirs { + os.RemoveAll(dir) + } + } +} + // nPeers = nValidators + nNotValidator func randConsensusNetWithPeers( nValidators, @@ -777,6 +799,19 @@ func randConsensusNetWithPeers( appFunc func(string) abci.Application, ) ([]*State, *types.GenesisDoc, *cfg.Config, cleanupFunc) { genDoc, privVals := randGenesisDoc(nValidators, false, testMinPower, types.DefaultVoterParams()) + css, peer0Config, configRootDirs := createPeersAndValidators(nValidators, nPeers, testName, + genDoc, privVals, tickerFunc, appFunc) + + return css, genDoc, peer0Config, func() { + for _, dir := range configRootDirs { + os.RemoveAll(dir) + } + } +} + +func createPeersAndValidators(nValidators, nPeers int, testName string, + genDoc *types.GenesisDoc, privVals []types.PrivValidator, tickerFunc func() TimeoutTicker, + appFunc func(string) abci.Application) ([]*State, *cfg.Config, []string) { css := make([]*State, nPeers) logger := consensusLogger() var peer0Config *cfg.Config @@ -819,11 +854,8 @@ func randConsensusNetWithPeers( css[i].SetTimeoutTicker(tickerFunc()) css[i].SetLogger(logger.With("validator", i, "module", "consensus")) } - return css, genDoc, peer0Config, func() { - for _, dir := range configRootDirs { - os.RemoveAll(dir) - } - } + + return css, peer0Config, configRootDirs } func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int { @@ -837,6 +869,41 @@ func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int { //------------------------------------------------------------------------------- // genesis +func genesisDoc( + numValidators int, + minPower int64, + voterParams *types.VoterParams, + nValsWithComposite int, +) (*types.GenesisDoc, []types.PrivValidator) { + validators := make([]types.GenesisValidator, numValidators) + privValidators := make([]types.PrivValidator, numValidators) + var val *types.Validator + var privVal types.PrivValidator + for i := 0; i < nValsWithComposite; i++ { + val, privVal = createTestValidator(minPower, types.PrivKeyComposite) + validators[i] = types.GenesisValidator{ + PubKey: val.PubKey, + Power: val.StakingPower, + } + privValidators[i] = privVal + } + for i := nValsWithComposite; i < numValidators; i++ { + val, privVal = createTestValidator(minPower, types.PrivKeyEd25519) + validators[i] = types.GenesisValidator{ + PubKey: val.PubKey, + Power: val.StakingPower, + } + privValidators[i] = privVal + } + sort.Sort(types.PrivValidatorsByAddress(privValidators)) + + return &types.GenesisDoc{ + GenesisTime: tmtime.Now(), + ChainID: config.ChainID(), + Validators: validators, + VoterParams: voterParams, + }, privValidators +} func randGenesisDoc( numValidators int, @@ -936,3 +1003,18 @@ func newPersistentKVStore() abci.Application { func newPersistentKVStoreWithPath(dbDir string) abci.Application { return kvstore.NewPersistentKVStoreApplication(dbDir) } + +//---------------------------------------- +// Validator +func createTestValidator(minPower int64, keytype types.PrivKeyType) (*types.Validator, types.PrivValidator) { + privVal := types.NewMockPV(keytype) + stakingPower := minPower + stakingPower += 100 + + pubKey, err := privVal.GetPubKey() + if err != nil { + panic(fmt.Errorf("could not retrieve pubkey %w", err)) + } + val := types.NewValidator(pubKey, stakingPower) + return val, privVal +} diff --git a/privval/file_test.go b/privval/file_test.go index 9b3ba2498..bf5376001 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -6,9 +6,12 @@ import ( "fmt" "io/ioutil" "os" + "reflect" "testing" "time" + "github.com/tendermint/tendermint/crypto/composite" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -17,6 +20,23 @@ import ( tmtime "github.com/tendermint/tendermint/types/time" ) +func TestGenFilePV(t *testing.T) { + tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_") + require.Nil(t, err) + tempStateFile, err := ioutil.TempFile("", "priv_validator_state_") + require.Nil(t, err) + + privValEd25519, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), PrivKeyTypeEd25519) + require.EqualValues(t, reflect.TypeOf(ed25519.PubKeyEd25519{}), reflect.TypeOf(privValEd25519.Key.PubKey)) + + privValComposite, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), PrivKeyTypeComposite) + require.EqualValues(t, reflect.TypeOf(composite.PubKeyComposite{}), reflect.TypeOf(privValComposite.Key.PubKey)) + + privValUndefinedPrivKeyType, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") + require.NotNil(t, err) + require.Nil(t, privValUndefinedPrivKeyType) +} + func TestGenLoadValidator(t *testing.T) { assert := assert.New(t)