func createProposalBlockSlim(cs *State, vs *validatorStub, round int32) (*types.Block, *types.PartSet) {
	var commit *types.Commit
	if cs.Height == 1 {
		commit = types.NewCommit(0, 0, types.BlockID{}, nil)
	} else {
		commit = cs.LastCommit.MakeCommit()
	}
	pubKey, _ := vs.GetPubKey()
	proposerAddr := pubKey.Address()
	message := cs.state.MakeHashMessage(round)
	proof, err := vs.GenerateVRFProof(message)
	if err != nil {
		cs.Logger.Error("enterPropose: Cannot generate vrf proof: %s", err.Error())
		return nil, nil
	}
	return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, round, proof, 0)
}
createProposalBlockSlim is copy from consensus/state.go:createProposalBlock and slimmed down
package consensus
import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"path"
	"path/filepath"
	"sort"
	"sync"
	"testing"
	"time"
	"github.com/go-kit/kit/log/term"
	"github.com/line/tm-db/v2/memdb"
	"github.com/stretchr/testify/require"
	dbm "github.com/line/tm-db/v2"
	abcicli "github.com/line/ostracon/abci/client"
	"github.com/line/ostracon/abci/example/counter"
	"github.com/line/ostracon/abci/example/kvstore"
	abci "github.com/line/ostracon/abci/types"
	cfg "github.com/line/ostracon/config"
	cstypes "github.com/line/ostracon/consensus/types"
	tmbytes "github.com/line/ostracon/libs/bytes"
	"github.com/line/ostracon/libs/log"
	tmos "github.com/line/ostracon/libs/os"
	tmpubsub "github.com/line/ostracon/libs/pubsub"
	tmsync "github.com/line/ostracon/libs/sync"
	mempl "github.com/line/ostracon/mempool"
	"github.com/line/ostracon/p2p"
	"github.com/line/ostracon/privval"
	tmproto "github.com/line/ostracon/proto/ostracon/types"
	sm "github.com/line/ostracon/state"
	"github.com/line/ostracon/store"
	"github.com/line/ostracon/types"
	tmtime "github.com/line/ostracon/types/time"
)
const (
	testSubscriber = "test-client"
)
type cleanupFunc func()
var config *cfg.Config  
var consensusReplayConfig *cfg.Config
var ensureTimeout = time.Millisecond * 200
func ensureDir(dir string, mode os.FileMode) {
	if err := tmos.EnsureDir(dir, mode); err != nil {
		panic(err)
	}
}
func ResetConfig(name string) *cfg.Config {
	return cfg.ResetTestRoot(name)
}
type validatorStub struct {
	Index  int32  
	Height int64
	Round  int32
	types.PrivValidator
	VotingPower int64
}
var testMinPower int64 = 10
func newValidatorStub(privValidator types.PrivValidator, valIndex int32) *validatorStub {
	return &validatorStub{
		Index:         valIndex,
		PrivValidator: privValidator,
		VotingPower:   testMinPower,
	}
}
func (vs *validatorStub) signVote(
	voteType tmproto.SignedMsgType,
	hash []byte,
	header types.PartSetHeader) (*types.Vote, error) {
	pubKey, err := vs.PrivValidator.GetPubKey()
	if err != nil {
		return nil, fmt.Errorf("can't get pubkey: %w", err)
	}
	vote := &types.Vote{
		ValidatorIndex:   vs.Index,
		ValidatorAddress: pubKey.Address(),
		Height:           vs.Height,
		Round:            vs.Round,
		Timestamp:        tmtime.Now(),
		Type:             voteType,
		BlockID:          types.BlockID{Hash: hash, PartSetHeader: header},
	}
	v := vote.ToProto()
	err = vs.PrivValidator.SignVote(config.ChainID(), v)
	vote.Signature = v.Signature
	return vote, err
}
func signVote(vs *validatorStub, voteType tmproto.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
	v, err := vs.signVote(voteType, hash, header)
	if err != nil {
		panic(fmt.Errorf("failed to sign vote: %v", err))
	}
	return v
}
func signVotes(
	voteType tmproto.SignedMsgType,
	hash []byte,
	header types.PartSetHeader,
	vss ...*validatorStub) []*types.Vote {
	votes := make([]*types.Vote, len(vss))
	for i, vs := range vss {
		votes[i] = signVote(vs, voteType, hash, header)
	}
	return votes
}
func incrementHeight(vss ...*validatorStub) {
	for _, vs := range vss {
		vs.Height++
	}
}
func incrementHeightByMap(vssMap map[string]*validatorStub) {
	for _, vs := range vssMap {
		vs.Height++
	}
}
func incrementRound(vss ...*validatorStub) {
	for _, vs := range vss {
		vs.Round++
	}
}
type ValidatorStubsByPower []*validatorStub
func (vss ValidatorStubsByPower) Len() int {
	return len(vss)
}
func (vss ValidatorStubsByPower) Less(i, j int) bool {
	vssi, err := vss[i].GetPubKey()
	if err != nil {
		panic(err)
	}
	vssj, err := vss[j].GetPubKey()
	if err != nil {
		panic(err)
	}
	if vss[i].VotingPower == vss[j].VotingPower {
		return bytes.Compare(vssi.Address(), vssj.Address()) == -1
	}
	return vss[i].VotingPower > vss[j].VotingPower
}
func (vss ValidatorStubsByPower) Swap(i, j int) {
	it := vss[i]
	vss[i] = vss[j]
	vss[i].Index = int32(i)
	vss[j] = it
	vss[j].Index = int32(j)
}
func startTestRound(cs *State, height int64, round int32) {
	cs.enterNewRound(height, round)
	cs.startRoutines(0)
}
func decideProposal(
	cs1 *State,
	vs *validatorStub,
	height int64,
	round int32,
) (proposal *types.Proposal, block *types.Block) {
	cs1.mtx.Lock()
	block, blockParts := createProposalBlockSlim(cs1, vs, round)
	validRound := cs1.ValidRound
	chainID := cs1.state.ChainID
	cs1.mtx.Unlock()
	if block == nil {
		panic("Failed to createProposalBlock. Did you forget to add commit for previous block?")
	}
	polRound, propBlockID := validRound, types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
	proposal = types.NewProposal(height, round, polRound, propBlockID)
	p := proposal.ToProto()
	if err := vs.SignProposal(chainID, p); err != nil {
		panic(err)
	}
	proposal.Signature = p.Signature
	return proposal, block
}