From b35e9ff53edd5a48ad992288aa243c7fbc3d687e Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Mon, 7 Dec 2020 22:16:18 +0100 Subject: [PATCH] node: improve test coverage on proposal block (#5748) ## Description Closes: #3156 --- node/node_test.go | 134 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 124 insertions(+), 10 deletions(-) diff --git a/node/node_test.go b/node/node_test.go index 375ec3c86..1daa826af 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -3,6 +3,7 @@ package node import ( "context" "fmt" + "math" "net" "os" "syscall" @@ -16,7 +17,9 @@ import ( "github.com/tendermint/tendermint/abci/example/kvstore" cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/evidence" "github.com/tendermint/tendermint/libs/log" tmrand "github.com/tendermint/tendermint/libs/rand" @@ -230,23 +233,22 @@ func TestCreateProposalBlock(t *testing.T) { logger := log.TestingLogger() - var height int64 = 1 + const height int64 = 1 state, stateDB, privVals := state(1, height) stateStore := sm.NewStore(stateDB) maxBytes := 16384 - var partSize uint32 = 256 + const partSize uint32 = 256 maxEvidenceBytes := int64(maxBytes / 2) state.ConsensusParams.Block.MaxBytes = int64(maxBytes) state.ConsensusParams.Evidence.MaxBytes = maxEvidenceBytes proposerAddr, _ := state.Validators.GetByIndex(0) // Make Mempool - memplMetrics := mempl.PrometheusMetrics("node_test_1") mempool := mempl.NewCListMempool( config.Mempool, proxyApp.Mempool(), state.LastBlockHeight, - mempl.WithMetrics(memplMetrics), + mempl.WithMetrics(mempl.NopMetrics()), mempl.WithPreCheck(sm.TxPreCheck(state)), mempl.WithPostCheck(sm.TxPostCheck(state)), ) @@ -314,7 +316,7 @@ func TestCreateProposalBlock(t *testing.T) { assert.NoError(t, err) } -func TestMaxProposalBlockSize(t *testing.T) { +func TestMaxTxsProposalBlockSize(t *testing.T) { config := cfg.ResetTestRoot("node_create_proposal") defer os.RemoveAll(config.RootDir) cc := proxy.NewLocalClientCreator(kvstore.NewApplication()) @@ -325,21 +327,20 @@ func TestMaxProposalBlockSize(t *testing.T) { logger := log.TestingLogger() - var height int64 = 1 + const height int64 = 1 state, stateDB, _ := state(1, height) stateStore := sm.NewStore(stateDB) - var maxBytes int64 = 16384 - var partSize uint32 = 256 + const maxBytes int64 = 16384 + const partSize uint32 = 256 state.ConsensusParams.Block.MaxBytes = maxBytes proposerAddr, _ := state.Validators.GetByIndex(0) // Make Mempool - memplMetrics := mempl.PrometheusMetrics("node_test_2") mempool := mempl.NewCListMempool( config.Mempool, proxyApp.Mempool(), state.LastBlockHeight, - mempl.WithMetrics(memplMetrics), + mempl.WithMetrics(mempl.NopMetrics()), mempl.WithPreCheck(sm.TxPreCheck(state)), mempl.WithPostCheck(sm.TxPostCheck(state)), ) @@ -375,6 +376,119 @@ func TestMaxProposalBlockSize(t *testing.T) { assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size())) } +func TestMaxProposalBlockSize(t *testing.T) { + config := cfg.ResetTestRoot("node_create_proposal") + defer os.RemoveAll(config.RootDir) + cc := proxy.NewLocalClientCreator(kvstore.NewApplication()) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.Nil(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + logger := log.TestingLogger() + + state, stateDB, _ := state(types.MaxVotesCount, int64(1)) + stateStore := sm.NewStore(stateDB) + const maxBytes int64 = 1024 * 1024 * 2 + state.ConsensusParams.Block.MaxBytes = maxBytes + proposerAddr, _ := state.Validators.GetByIndex(0) + + // Make Mempool + mempool := mempl.NewCListMempool( + config.Mempool, + proxyApp.Mempool(), + state.LastBlockHeight, + mempl.WithMetrics(mempl.NopMetrics()), + mempl.WithPreCheck(sm.TxPreCheck(state)), + mempl.WithPostCheck(sm.TxPostCheck(state)), + ) + mempool.SetLogger(logger) + + // fill the mempool with one txs just below the maximum size + txLength := int(types.MaxDataBytesNoEvidence(maxBytes, types.MaxVotesCount)) + tx := tmrand.Bytes(txLength - 6) // to account for the varint + err = mempool.CheckTx(tx, nil, mempl.TxInfo{}) + assert.NoError(t, err) + // now produce more txs than what a normal block can hold with 10 smaller txs + // At the end of the test, only the single big tx should be added + for i := 0; i < 10; i++ { + tx := tmrand.Bytes(10) + err = mempool.CheckTx(tx, nil, mempl.TxInfo{}) + assert.NoError(t, err) + } + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp.Consensus(), + mempool, + sm.EmptyEvidencePool{}, + ) + + blockID := types.BlockID{ + Hash: tmhash.Sum([]byte("blockID_hash")), + PartSetHeader: types.PartSetHeader{ + Total: math.MaxInt32, + Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")), + }, + } + + timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) + // change state in order to produce the largest accepted header + state.LastBlockID = blockID + state.LastBlockHeight = math.MaxInt64 - 1 + state.LastBlockTime = timestamp + state.LastResultsHash = tmhash.Sum([]byte("last_results_hash")) + state.AppHash = tmhash.Sum([]byte("app_hash")) + state.Version.Consensus.Block = math.MaxInt64 + state.Version.Consensus.App = math.MaxInt64 + maxChainID := "" + for i := 0; i < types.MaxChainIDLen; i++ { + maxChainID += "𠜎" + } + state.ChainID = maxChainID + + cs := types.CommitSig{ + BlockIDFlag: types.BlockIDFlagNil, + ValidatorAddress: crypto.AddressHash([]byte("validator_address")), + Timestamp: timestamp, + Signature: crypto.CRandBytes(types.MaxSignatureSize), + } + + commit := &types.Commit{ + Height: math.MaxInt64, + Round: math.MaxInt32, + BlockID: blockID, + } + + // add maximum amount of signatures to a single commit + for i := 0; i < types.MaxVotesCount; i++ { + commit.Signatures = append(commit.Signatures, cs) + } + + block, partSet := blockExec.CreateProposalBlock( + math.MaxInt64, + state, commit, + proposerAddr, + ) + + // this ensures that the header is at max size + block.Header.Time = timestamp + + pb, err := block.ToProto() + require.NoError(t, err) + + // require that the header and commit be the max possible size + require.Equal(t, int64(pb.Header.Size()), types.MaxHeaderBytes) + require.Equal(t, int64(pb.LastCommit.Size()), types.MaxCommitBytes(types.MaxVotesCount)) + // make sure that the block is less than the max possible size + assert.Equal(t, int64(pb.Size()), maxBytes) + // because of the proto overhead we expect the part set bytes to be equal or + // less than the pb block size + assert.LessOrEqual(t, partSet.ByteSize(), int64(pb.Size())) + +} + func TestNodeNewNodeCustomReactors(t *testing.T) { config := cfg.ResetTestRoot("node_new_node_custom_reactors_test") defer os.RemoveAll(config.RootDir)