github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/state/helpers_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"math/rand"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	dbm "github.com/tendermint/tm-db"
    13  
    14  	abci "github.com/ari-anchor/sei-tendermint/abci/types"
    15  	"github.com/ari-anchor/sei-tendermint/crypto"
    16  	"github.com/ari-anchor/sei-tendermint/crypto/ed25519"
    17  	"github.com/ari-anchor/sei-tendermint/crypto/encoding"
    18  	sm "github.com/ari-anchor/sei-tendermint/internal/state"
    19  	sf "github.com/ari-anchor/sei-tendermint/internal/state/test/factory"
    20  	"github.com/ari-anchor/sei-tendermint/internal/test/factory"
    21  	tmtime "github.com/ari-anchor/sei-tendermint/libs/time"
    22  	tmproto "github.com/ari-anchor/sei-tendermint/proto/tendermint/types"
    23  	"github.com/ari-anchor/sei-tendermint/types"
    24  )
    25  
    26  type paramsChangeTestCase struct {
    27  	height int64
    28  	params types.ConsensusParams
    29  }
    30  
    31  func makeAndCommitGoodBlock(
    32  	ctx context.Context,
    33  	t *testing.T,
    34  	state sm.State,
    35  	height int64,
    36  	lastCommit *types.Commit,
    37  	proposerAddr []byte,
    38  	blockExec *sm.BlockExecutor,
    39  	privVals map[string]types.PrivValidator,
    40  	evidence []types.Evidence,
    41  ) (sm.State, types.BlockID, *types.ExtendedCommit) {
    42  	t.Helper()
    43  
    44  	// A good block passes
    45  	state, blockID := makeAndApplyGoodBlock(ctx, t, state, height, lastCommit, proposerAddr, blockExec, evidence)
    46  
    47  	// Simulate a lastCommit for this block from all validators for the next height
    48  	commit, _ := makeValidCommit(ctx, t, height, blockID, state.Validators, privVals)
    49  
    50  	return state, blockID, commit
    51  }
    52  
    53  func makeAndApplyGoodBlock(
    54  	ctx context.Context,
    55  	t *testing.T,
    56  	state sm.State,
    57  	height int64,
    58  	lastCommit *types.Commit,
    59  	proposerAddr []byte,
    60  	blockExec *sm.BlockExecutor,
    61  	evidence []types.Evidence,
    62  ) (sm.State, types.BlockID) {
    63  	t.Helper()
    64  	block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr)
    65  	partSet, err := block.MakePartSet(types.BlockPartSizeBytes)
    66  	require.NoError(t, err)
    67  
    68  	require.NoError(t, blockExec.ValidateBlock(ctx, state, block))
    69  	blockID := types.BlockID{Hash: block.Hash(),
    70  		PartSetHeader: partSet.Header()}
    71  	state, err = blockExec.ApplyBlock(ctx, state, blockID, block, nil)
    72  	require.NoError(t, err)
    73  
    74  	return state, blockID
    75  }
    76  
    77  func makeValidCommit(
    78  	ctx context.Context,
    79  	t *testing.T,
    80  	height int64,
    81  	blockID types.BlockID,
    82  	vals *types.ValidatorSet,
    83  	privVals map[string]types.PrivValidator,
    84  ) (*types.ExtendedCommit, []*types.Vote) {
    85  	t.Helper()
    86  	sigs := make([]types.ExtendedCommitSig, vals.Size())
    87  	votes := make([]*types.Vote, vals.Size())
    88  	for i := 0; i < vals.Size(); i++ {
    89  		_, val := vals.GetByIndex(int32(i))
    90  		vote, err := factory.MakeVote(ctx, privVals[val.Address.String()], chainID, int32(i), height, 0, 2, blockID, time.Now())
    91  		require.NoError(t, err)
    92  		sigs[i] = vote.ExtendedCommitSig()
    93  		votes[i] = vote
    94  	}
    95  
    96  	return &types.ExtendedCommit{
    97  		Height:             height,
    98  		BlockID:            blockID,
    99  		ExtendedSignatures: sigs,
   100  	}, votes
   101  }
   102  
   103  func makeState(t *testing.T, nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
   104  	vals := make([]types.GenesisValidator, nVals)
   105  	privVals := make(map[string]types.PrivValidator, nVals)
   106  	for i := 0; i < nVals; i++ {
   107  		secret := []byte(fmt.Sprintf("test%d", i))
   108  		pk := ed25519.GenPrivKeyFromSecret(secret)
   109  		valAddr := pk.PubKey().Address()
   110  		vals[i] = types.GenesisValidator{
   111  			Address: valAddr,
   112  			PubKey:  pk.PubKey(),
   113  			Power:   1000,
   114  			Name:    fmt.Sprintf("test%d", i),
   115  		}
   116  		privVals[valAddr.String()] = types.NewMockPVWithParams(pk, false, false)
   117  	}
   118  	s, _ := sm.MakeGenesisState(&types.GenesisDoc{
   119  		ChainID:    chainID,
   120  		Validators: vals,
   121  		AppHash:    nil,
   122  	})
   123  
   124  	stateDB := dbm.NewMemDB()
   125  	stateStore := sm.NewStore(stateDB)
   126  	require.NoError(t, stateStore.Save(s))
   127  
   128  	for i := 1; i < height; i++ {
   129  		s.LastBlockHeight++
   130  		s.LastValidators = s.Validators.Copy()
   131  
   132  		require.NoError(t, stateStore.Save(s))
   133  	}
   134  
   135  	return s, stateDB, privVals
   136  }
   137  
   138  func genValSet(size int) *types.ValidatorSet {
   139  	vals := make([]*types.Validator, size)
   140  	for i := 0; i < size; i++ {
   141  		vals[i] = types.NewValidator(ed25519.GenPrivKey().PubKey(), 10)
   142  	}
   143  	return types.NewValidatorSet(vals)
   144  }
   145  
   146  func makeHeaderPartsResponsesValPubKeyChange(
   147  	t *testing.T,
   148  	state sm.State,
   149  	pubkey crypto.PubKey,
   150  ) (types.Header, types.BlockID, *abci.ResponseFinalizeBlock) {
   151  
   152  	block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
   153  	finalizeBlockResponses := &abci.ResponseFinalizeBlock{}
   154  	// If the pubkey is new, remove the old and add the new.
   155  	_, val := state.NextValidators.GetByIndex(0)
   156  	if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
   157  		vPbPk, err := encoding.PubKeyToProto(val.PubKey)
   158  		require.NoError(t, err)
   159  		pbPk, err := encoding.PubKeyToProto(pubkey)
   160  		require.NoError(t, err)
   161  
   162  		finalizeBlockResponses.ValidatorUpdates = []abci.ValidatorUpdate{
   163  			{PubKey: vPbPk, Power: 0},
   164  			{PubKey: pbPk, Power: 10},
   165  		}
   166  	}
   167  
   168  	return block.Header, types.BlockID{Hash: block.Hash(), PartSetHeader: types.PartSetHeader{}}, finalizeBlockResponses
   169  }
   170  
   171  func makeHeaderPartsResponsesValPowerChange(
   172  	t *testing.T,
   173  	state sm.State,
   174  	power int64,
   175  ) (types.Header, types.BlockID, *abci.ResponseFinalizeBlock) {
   176  	t.Helper()
   177  
   178  	block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
   179  	finalizeBlockResponses := &abci.ResponseFinalizeBlock{}
   180  
   181  	// If the pubkey is new, remove the old and add the new.
   182  	_, val := state.NextValidators.GetByIndex(0)
   183  	if val.VotingPower != power {
   184  		vPbPk, err := encoding.PubKeyToProto(val.PubKey)
   185  		require.NoError(t, err)
   186  
   187  		finalizeBlockResponses.ValidatorUpdates = []abci.ValidatorUpdate{
   188  			{PubKey: vPbPk, Power: power},
   189  		}
   190  	}
   191  
   192  	return block.Header, types.BlockID{Hash: block.Hash(), PartSetHeader: types.PartSetHeader{}}, finalizeBlockResponses
   193  }
   194  
   195  func makeHeaderPartsResponsesParams(
   196  	t *testing.T,
   197  	state sm.State,
   198  	params *types.ConsensusParams,
   199  ) (types.Header, types.BlockID, *abci.ResponseFinalizeBlock) {
   200  	t.Helper()
   201  
   202  	block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
   203  	pbParams := params.ToProto()
   204  	finalizeBlockResponses := &abci.ResponseFinalizeBlock{ConsensusParamUpdates: &pbParams}
   205  	return block.Header, types.BlockID{Hash: block.Hash(), PartSetHeader: types.PartSetHeader{}}, finalizeBlockResponses
   206  }
   207  
   208  func randomGenesisDoc() *types.GenesisDoc {
   209  	pubkey := ed25519.GenPrivKey().PubKey()
   210  	return &types.GenesisDoc{
   211  		GenesisTime: tmtime.Now(),
   212  		ChainID:     "abc",
   213  		Validators: []types.GenesisValidator{
   214  			{
   215  				Address: pubkey.Address(),
   216  				PubKey:  pubkey,
   217  				Power:   10,
   218  				Name:    "myval",
   219  			},
   220  		},
   221  		ConsensusParams: types.DefaultConsensusParams(),
   222  	}
   223  }
   224  
   225  // used for testing by state store
   226  func makeRandomStateFromValidatorSet(
   227  	lastValSet *types.ValidatorSet,
   228  	height, lastHeightValidatorsChanged int64,
   229  ) sm.State {
   230  	return sm.State{
   231  		LastBlockHeight:                  height - 1,
   232  		NextValidators:                   lastValSet.CopyIncrementProposerPriority(2),
   233  		Validators:                       lastValSet.CopyIncrementProposerPriority(1),
   234  		LastValidators:                   lastValSet.Copy(),
   235  		LastHeightConsensusParamsChanged: height,
   236  		ConsensusParams:                  *types.DefaultConsensusParams(),
   237  		LastHeightValidatorsChanged:      lastHeightValidatorsChanged,
   238  		InitialHeight:                    1,
   239  	}
   240  }
   241  func makeRandomStateFromConsensusParams(
   242  	ctx context.Context,
   243  	t *testing.T,
   244  	consensusParams *types.ConsensusParams,
   245  	height,
   246  	lastHeightConsensusParamsChanged int64,
   247  ) sm.State {
   248  	t.Helper()
   249  	val, _, err := factory.Validator(ctx, 10+int64(rand.Uint32()))
   250  	require.NoError(t, err)
   251  	valSet := types.NewValidatorSet([]*types.Validator{val})
   252  	return sm.State{
   253  		LastBlockHeight:                  height - 1,
   254  		ConsensusParams:                  *consensusParams,
   255  		LastHeightConsensusParamsChanged: lastHeightConsensusParamsChanged,
   256  		NextValidators:                   valSet.CopyIncrementProposerPriority(2),
   257  		Validators:                       valSet.CopyIncrementProposerPriority(1),
   258  		LastValidators:                   valSet.Copy(),
   259  		LastHeightValidatorsChanged:      height,
   260  		InitialHeight:                    1,
   261  	}
   262  }
   263  
   264  //----------------------------------------------------------------------------
   265  
   266  type testApp struct {
   267  	abci.BaseApplication
   268  
   269  	CommitVotes         []abci.VoteInfo
   270  	ByzantineValidators []abci.Misbehavior
   271  	ValidatorUpdates    []abci.ValidatorUpdate
   272  }
   273  
   274  var _ abci.Application = (*testApp)(nil)
   275  
   276  func (app *testApp) Info(_ context.Context, req *abci.RequestInfo) (*abci.ResponseInfo, error) {
   277  	return &abci.ResponseInfo{}, nil
   278  }
   279  
   280  func (app *testApp) FinalizeBlock(_ context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
   281  	app.CommitVotes = req.DecidedLastCommit.Votes
   282  	app.ByzantineValidators = req.ByzantineValidators
   283  
   284  	resTxs := make([]*abci.ExecTxResult, len(req.Txs))
   285  	for i, tx := range req.Txs {
   286  		if len(tx) > 0 {
   287  			resTxs[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
   288  		} else {
   289  			resTxs[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK + 10} // error
   290  		}
   291  	}
   292  
   293  	return &abci.ResponseFinalizeBlock{
   294  		ValidatorUpdates: app.ValidatorUpdates,
   295  		ConsensusParamUpdates: &tmproto.ConsensusParams{
   296  			Version: &tmproto.VersionParams{
   297  				AppVersion: 1,
   298  			},
   299  		},
   300  		Events:    []abci.Event{},
   301  		TxResults: resTxs,
   302  	}, nil
   303  }
   304  
   305  func (app *testApp) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) {
   306  	return &abci.ResponseCheckTx{}, nil
   307  }
   308  
   309  func (app *testApp) Commit(context.Context) (*abci.ResponseCommit, error) {
   310  	return &abci.ResponseCommit{RetainHeight: 1}, nil
   311  }
   312  
   313  func (app *testApp) Query(_ context.Context, req *abci.RequestQuery) (*abci.ResponseQuery, error) {
   314  	return &abci.ResponseQuery{}, nil
   315  }
   316  
   317  func (app *testApp) ProcessProposal(_ context.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) {
   318  	for _, tx := range req.Txs {
   319  		if len(tx) == 0 {
   320  			return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil
   321  		}
   322  	}
   323  	return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
   324  }