github.com/evdatsion/aphelion-dpos-bft@v0.32.1/consensus/replay_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"sort"
    19  
    20  	"github.com/evdatsion/aphelion-dpos-bft/abci/example/kvstore"
    21  	abci "github.com/evdatsion/aphelion-dpos-bft/abci/types"
    22  	cfg "github.com/evdatsion/aphelion-dpos-bft/config"
    23  	"github.com/evdatsion/aphelion-dpos-bft/crypto"
    24  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
    25  	dbm "github.com/evdatsion/aphelion-dpos-bft/libs/db"
    26  	"github.com/evdatsion/aphelion-dpos-bft/libs/log"
    27  	"github.com/evdatsion/aphelion-dpos-bft/mock"
    28  	"github.com/evdatsion/aphelion-dpos-bft/privval"
    29  	"github.com/evdatsion/aphelion-dpos-bft/proxy"
    30  	sm "github.com/evdatsion/aphelion-dpos-bft/state"
    31  	"github.com/evdatsion/aphelion-dpos-bft/types"
    32  	tmtime "github.com/evdatsion/aphelion-dpos-bft/types/time"
    33  	"github.com/evdatsion/aphelion-dpos-bft/version"
    34  )
    35  
    36  func TestMain(m *testing.M) {
    37  	config = ResetConfig("consensus_reactor_test")
    38  	consensusReplayConfig = ResetConfig("consensus_replay_test")
    39  	configStateTest := ResetConfig("consensus_state_test")
    40  	configMempoolTest := ResetConfig("consensus_mempool_test")
    41  	configByzantineTest := ResetConfig("consensus_byzantine_test")
    42  	code := m.Run()
    43  	os.RemoveAll(config.RootDir)
    44  	os.RemoveAll(consensusReplayConfig.RootDir)
    45  	os.RemoveAll(configStateTest.RootDir)
    46  	os.RemoveAll(configMempoolTest.RootDir)
    47  	os.RemoveAll(configByzantineTest.RootDir)
    48  	os.Exit(code)
    49  }
    50  
    51  // These tests ensure we can always recover from failure at any part of the consensus process.
    52  // There are two general failure scenarios: failure during consensus, and failure while applying the block.
    53  // Only the latter interacts with the app and store,
    54  // but the former has to deal with restrictions on re-use of priv_validator keys.
    55  // The `WAL Tests` are for failures during the consensus;
    56  // the `Handshake Tests` are for failures in applying the block.
    57  // With the help of the WAL, we can recover from it all!
    58  
    59  //------------------------------------------------------------------------------------------
    60  // WAL Tests
    61  
    62  // TODO: It would be better to verify explicitly which states we can recover from without the wal
    63  // and which ones we need the wal for - then we'd also be able to only flush the
    64  // wal writer when we need to, instead of with every message.
    65  
    66  func startNewConsensusStateAndWaitForBlock(t *testing.T, consensusReplayConfig *cfg.Config,
    67  	lastBlockHeight int64, blockDB dbm.DB, stateDB dbm.DB) {
    68  	logger := log.TestingLogger()
    69  	state, _ := sm.LoadStateFromDBOrGenesisFile(stateDB, consensusReplayConfig.GenesisFile())
    70  	privValidator := loadPrivValidator(consensusReplayConfig)
    71  	cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
    72  	cs.SetLogger(logger)
    73  
    74  	bytes, _ := ioutil.ReadFile(cs.config.WalFile())
    75  	t.Logf("====== WAL: \n\r%X\n", bytes)
    76  
    77  	err := cs.Start()
    78  	require.NoError(t, err)
    79  	defer cs.Stop()
    80  
    81  	// This is just a signal that we haven't halted; its not something contained
    82  	// in the WAL itself. Assuming the consensus state is running, replay of any
    83  	// WAL, including the empty one, should eventually be followed by a new
    84  	// block, or else something is wrong.
    85  	newBlockSub, err := cs.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock)
    86  	require.NoError(t, err)
    87  	select {
    88  	case <-newBlockSub.Out():
    89  	case <-newBlockSub.Cancelled():
    90  		t.Fatal("newBlockSub was cancelled")
    91  	case <-time.After(120 * time.Second):
    92  		t.Fatal("Timed out waiting for new block (see trace above)")
    93  	}
    94  }
    95  
    96  func sendTxs(ctx context.Context, cs *ConsensusState) {
    97  	for i := 0; i < 256; i++ {
    98  		select {
    99  		case <-ctx.Done():
   100  			return
   101  		default:
   102  			tx := []byte{byte(i)}
   103  			assertMempool(cs.txNotifier).CheckTx(tx, nil)
   104  			i++
   105  		}
   106  	}
   107  }
   108  
   109  // TestWALCrash uses crashing WAL to test we can recover from any WAL failure.
   110  func TestWALCrash(t *testing.T) {
   111  	testCases := []struct {
   112  		name         string
   113  		initFn       func(dbm.DB, *ConsensusState, context.Context)
   114  		heightToStop int64
   115  	}{
   116  		{"empty block",
   117  			func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {},
   118  			1},
   119  		{"many non-empty blocks",
   120  			func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {
   121  				go sendTxs(ctx, cs)
   122  			},
   123  			3},
   124  	}
   125  
   126  	for i, tc := range testCases {
   127  		consensusReplayConfig := ResetConfig(fmt.Sprintf("%s_%d", t.Name(), i))
   128  		t.Run(tc.name, func(t *testing.T) {
   129  			crashWALandCheckLiveness(t, consensusReplayConfig, tc.initFn, tc.heightToStop)
   130  		})
   131  	}
   132  }
   133  
   134  func crashWALandCheckLiveness(t *testing.T, consensusReplayConfig *cfg.Config,
   135  	initFn func(dbm.DB, *ConsensusState, context.Context), heightToStop int64) {
   136  	walPanicked := make(chan error)
   137  	crashingWal := &crashingWAL{panicCh: walPanicked, heightToStop: heightToStop}
   138  
   139  	i := 1
   140  LOOP:
   141  	for {
   142  		t.Logf("====== LOOP %d\n", i)
   143  
   144  		// create consensus state from a clean slate
   145  		logger := log.NewNopLogger()
   146  		blockDB := dbm.NewMemDB()
   147  		stateDB := blockDB
   148  		state, _ := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
   149  		privValidator := loadPrivValidator(consensusReplayConfig)
   150  		cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
   151  		cs.SetLogger(logger)
   152  
   153  		// start sending transactions
   154  		ctx, cancel := context.WithCancel(context.Background())
   155  		initFn(stateDB, cs, ctx)
   156  
   157  		// clean up WAL file from the previous iteration
   158  		walFile := cs.config.WalFile()
   159  		os.Remove(walFile)
   160  
   161  		// set crashing WAL
   162  		csWal, err := cs.OpenWAL(walFile)
   163  		require.NoError(t, err)
   164  		crashingWal.next = csWal
   165  		// reset the message counter
   166  		crashingWal.msgIndex = 1
   167  		cs.wal = crashingWal
   168  
   169  		// start consensus state
   170  		err = cs.Start()
   171  		require.NoError(t, err)
   172  
   173  		i++
   174  
   175  		select {
   176  		case err := <-walPanicked:
   177  			t.Logf("WAL panicked: %v", err)
   178  
   179  			// make sure we can make blocks after a crash
   180  			startNewConsensusStateAndWaitForBlock(t, consensusReplayConfig, cs.Height, blockDB, stateDB)
   181  
   182  			// stop consensus state and transactions sender (initFn)
   183  			cs.Stop()
   184  			cancel()
   185  
   186  			// if we reached the required height, exit
   187  			if _, ok := err.(ReachedHeightToStopError); ok {
   188  				break LOOP
   189  			}
   190  		case <-time.After(10 * time.Second):
   191  			t.Fatal("WAL did not panic for 10 seconds (check the log)")
   192  		}
   193  	}
   194  }
   195  
   196  // crashingWAL is a WAL which crashes or rather simulates a crash during Save
   197  // (before and after). It remembers a message for which we last panicked
   198  // (lastPanickedForMsgIndex), so we don't panic for it in subsequent iterations.
   199  type crashingWAL struct {
   200  	next         WAL
   201  	panicCh      chan error
   202  	heightToStop int64
   203  
   204  	msgIndex                int // current message index
   205  	lastPanickedForMsgIndex int // last message for which we panicked
   206  }
   207  
   208  var _ WAL = &crashingWAL{}
   209  
   210  // WALWriteError indicates a WAL crash.
   211  type WALWriteError struct {
   212  	msg string
   213  }
   214  
   215  func (e WALWriteError) Error() string {
   216  	return e.msg
   217  }
   218  
   219  // ReachedHeightToStopError indicates we've reached the required consensus
   220  // height and may exit.
   221  type ReachedHeightToStopError struct {
   222  	height int64
   223  }
   224  
   225  func (e ReachedHeightToStopError) Error() string {
   226  	return fmt.Sprintf("reached height to stop %d", e.height)
   227  }
   228  
   229  // Write simulate WAL's crashing by sending an error to the panicCh and then
   230  // exiting the cs.receiveRoutine.
   231  func (w *crashingWAL) Write(m WALMessage) {
   232  	if endMsg, ok := m.(EndHeightMessage); ok {
   233  		if endMsg.Height == w.heightToStop {
   234  			w.panicCh <- ReachedHeightToStopError{endMsg.Height}
   235  			runtime.Goexit()
   236  		} else {
   237  			w.next.Write(m)
   238  		}
   239  		return
   240  	}
   241  
   242  	if w.msgIndex > w.lastPanickedForMsgIndex {
   243  		w.lastPanickedForMsgIndex = w.msgIndex
   244  		_, file, line, _ := runtime.Caller(1)
   245  		w.panicCh <- WALWriteError{fmt.Sprintf("failed to write %T to WAL (fileline: %s:%d)", m, file, line)}
   246  		runtime.Goexit()
   247  	} else {
   248  		w.msgIndex++
   249  		w.next.Write(m)
   250  	}
   251  }
   252  
   253  func (w *crashingWAL) WriteSync(m WALMessage) {
   254  	w.Write(m)
   255  }
   256  
   257  func (w *crashingWAL) FlushAndSync() error { return w.next.FlushAndSync() }
   258  
   259  func (w *crashingWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
   260  	return w.next.SearchForEndHeight(height, options)
   261  }
   262  
   263  func (w *crashingWAL) Start() error { return w.next.Start() }
   264  func (w *crashingWAL) Stop() error  { return w.next.Stop() }
   265  func (w *crashingWAL) Wait()        { w.next.Wait() }
   266  
   267  //------------------------------------------------------------------------------------------
   268  type testSim struct {
   269  	GenesisState sm.State
   270  	Config       *cfg.Config
   271  	Chain        []*types.Block
   272  	Commits      []*types.Commit
   273  	CleanupFunc  cleanupFunc
   274  }
   275  
   276  const (
   277  	numBlocks = 6
   278  )
   279  
   280  var (
   281  	mempool = mock.Mempool{}
   282  	evpool  = sm.MockEvidencePool{}
   283  
   284  	sim testSim
   285  )
   286  
   287  //---------------------------------------
   288  // Test handshake/replay
   289  
   290  // 0 - all synced up
   291  // 1 - saved block but app and state are behind
   292  // 2 - save block and committed but state is behind
   293  var modes = []uint{0, 1, 2}
   294  
   295  // This is actually not a test, it's for storing validator change tx data for testHandshakeReplay
   296  func TestSimulateValidatorsChange(t *testing.T) {
   297  	nPeers := 7
   298  	nVals := 4
   299  	css, genDoc, config, cleanup := randConsensusNetWithPeers(nVals, nPeers, "replay_test", newMockTickerFunc(true), newPersistentKVStoreWithPath)
   300  	sim.Config = config
   301  	sim.GenesisState, _ = sm.MakeGenesisState(genDoc)
   302  	sim.CleanupFunc = cleanup
   303  
   304  	partSize := types.BlockPartSizeBytes
   305  
   306  	newRoundCh := subscribe(css[0].eventBus, types.EventQueryNewRound)
   307  	proposalCh := subscribe(css[0].eventBus, types.EventQueryCompleteProposal)
   308  
   309  	vss := make([]*validatorStub, nPeers)
   310  	for i := 0; i < nPeers; i++ {
   311  		vss[i] = NewValidatorStub(css[i].privValidator, i)
   312  	}
   313  	height, round := css[0].Height, css[0].Round
   314  	// start the machine
   315  	startTestRound(css[0], height, round)
   316  	incrementHeight(vss...)
   317  	ensureNewRound(newRoundCh, height, 0)
   318  	ensureNewProposal(proposalCh, height, round)
   319  	rs := css[0].GetRoundState()
   320  	signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:nVals]...)
   321  	ensureNewRound(newRoundCh, height+1, 0)
   322  
   323  	//height 2
   324  	height++
   325  	incrementHeight(vss...)
   326  	newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
   327  	valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1)
   328  	newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
   329  	err := assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil)
   330  	assert.Nil(t, err)
   331  	propBlock, _ := css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
   332  	propBlockParts := propBlock.MakePartSet(partSize)
   333  	blockID := types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
   334  	proposal := types.NewProposal(vss[1].Height, round, -1, blockID)
   335  	if err := vss[1].SignProposal(config.ChainID(), proposal); err != nil {
   336  		t.Fatal("failed to sign bad proposal", err)
   337  	}
   338  
   339  	// set the proposal block
   340  	if err := css[0].SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   341  		t.Fatal(err)
   342  	}
   343  	ensureNewProposal(proposalCh, height, round)
   344  	rs = css[0].GetRoundState()
   345  	signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:nVals]...)
   346  	ensureNewRound(newRoundCh, height+1, 0)
   347  
   348  	//height 3
   349  	height++
   350  	incrementHeight(vss...)
   351  	updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
   352  	updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1)
   353  	updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
   354  	err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil)
   355  	assert.Nil(t, err)
   356  	propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
   357  	propBlockParts = propBlock.MakePartSet(partSize)
   358  	blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
   359  	proposal = types.NewProposal(vss[2].Height, round, -1, blockID)
   360  	if err := vss[2].SignProposal(config.ChainID(), proposal); err != nil {
   361  		t.Fatal("failed to sign bad proposal", err)
   362  	}
   363  
   364  	// set the proposal block
   365  	if err := css[0].SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   366  		t.Fatal(err)
   367  	}
   368  	ensureNewProposal(proposalCh, height, round)
   369  	rs = css[0].GetRoundState()
   370  	signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:nVals]...)
   371  	ensureNewRound(newRoundCh, height+1, 0)
   372  
   373  	//height 4
   374  	height++
   375  	incrementHeight(vss...)
   376  	newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
   377  	newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2)
   378  	newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
   379  	err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx2, nil)
   380  	assert.Nil(t, err)
   381  	newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
   382  	newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3)
   383  	newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
   384  	err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil)
   385  	assert.Nil(t, err)
   386  	propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
   387  	propBlockParts = propBlock.MakePartSet(partSize)
   388  	blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
   389  	newVss := make([]*validatorStub, nVals+1)
   390  	copy(newVss, vss[:nVals+1])
   391  	sort.Sort(ValidatorStubsByAddress(newVss))
   392  	selfIndex := 0
   393  	for i, vs := range newVss {
   394  		if vs.GetPubKey().Equals(css[0].privValidator.GetPubKey()) {
   395  			selfIndex = i
   396  			break
   397  		}
   398  	}
   399  
   400  	proposal = types.NewProposal(vss[3].Height, round, -1, blockID)
   401  	if err := vss[3].SignProposal(config.ChainID(), proposal); err != nil {
   402  		t.Fatal("failed to sign bad proposal", err)
   403  	}
   404  
   405  	// set the proposal block
   406  	if err := css[0].SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  	ensureNewProposal(proposalCh, height, round)
   410  
   411  	removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
   412  	err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx2, nil)
   413  	assert.Nil(t, err)
   414  
   415  	rs = css[0].GetRoundState()
   416  	for i := 0; i < nVals+1; i++ {
   417  		if i == selfIndex {
   418  			continue
   419  		}
   420  		signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), newVss[i])
   421  	}
   422  
   423  	ensureNewRound(newRoundCh, height+1, 0)
   424  
   425  	//height 5
   426  	height++
   427  	incrementHeight(vss...)
   428  	ensureNewProposal(proposalCh, height, round)
   429  	rs = css[0].GetRoundState()
   430  	for i := 0; i < nVals+1; i++ {
   431  		if i == selfIndex {
   432  			continue
   433  		}
   434  		signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), newVss[i])
   435  	}
   436  	ensureNewRound(newRoundCh, height+1, 0)
   437  
   438  	//height 6
   439  	height++
   440  	incrementHeight(vss...)
   441  	removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
   442  	err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil)
   443  	assert.Nil(t, err)
   444  	propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
   445  	propBlockParts = propBlock.MakePartSet(partSize)
   446  	blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
   447  	newVss = make([]*validatorStub, nVals+3)
   448  	copy(newVss, vss[:nVals+3])
   449  	sort.Sort(ValidatorStubsByAddress(newVss))
   450  	for i, vs := range newVss {
   451  		if vs.GetPubKey().Equals(css[0].privValidator.GetPubKey()) {
   452  			selfIndex = i
   453  			break
   454  		}
   455  	}
   456  	proposal = types.NewProposal(vss[1].Height, round, -1, blockID)
   457  	if err := vss[1].SignProposal(config.ChainID(), proposal); err != nil {
   458  		t.Fatal("failed to sign bad proposal", err)
   459  	}
   460  
   461  	// set the proposal block
   462  	if err := css[0].SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   463  		t.Fatal(err)
   464  	}
   465  	ensureNewProposal(proposalCh, height, round)
   466  	rs = css[0].GetRoundState()
   467  	for i := 0; i < nVals+3; i++ {
   468  		if i == selfIndex {
   469  			continue
   470  		}
   471  		signAddVotes(css[0], types.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), newVss[i])
   472  	}
   473  	ensureNewRound(newRoundCh, height+1, 0)
   474  
   475  	sim.Chain = make([]*types.Block, 0)
   476  	sim.Commits = make([]*types.Commit, 0)
   477  	for i := 1; i <= numBlocks; i++ {
   478  		sim.Chain = append(sim.Chain, css[0].blockStore.LoadBlock(int64(i)))
   479  		sim.Commits = append(sim.Commits, css[0].blockStore.LoadBlockCommit(int64(i)))
   480  	}
   481  }
   482  
   483  // Sync from scratch
   484  func TestHandshakeReplayAll(t *testing.T) {
   485  	for _, m := range modes {
   486  		testHandshakeReplay(t, config, 0, m, false)
   487  	}
   488  	for _, m := range modes {
   489  		testHandshakeReplay(t, config, 0, m, true)
   490  	}
   491  }
   492  
   493  // Sync many, not from scratch
   494  func TestHandshakeReplaySome(t *testing.T) {
   495  	for _, m := range modes {
   496  		testHandshakeReplay(t, config, 1, m, false)
   497  	}
   498  	for _, m := range modes {
   499  		testHandshakeReplay(t, config, 1, m, true)
   500  	}
   501  }
   502  
   503  // Sync from lagging by one
   504  func TestHandshakeReplayOne(t *testing.T) {
   505  	for _, m := range modes {
   506  		testHandshakeReplay(t, config, numBlocks-1, m, false)
   507  	}
   508  	for _, m := range modes {
   509  		testHandshakeReplay(t, config, numBlocks-1, m, true)
   510  	}
   511  }
   512  
   513  // Sync from caught up
   514  func TestHandshakeReplayNone(t *testing.T) {
   515  	for _, m := range modes {
   516  		testHandshakeReplay(t, config, numBlocks, m, false)
   517  	}
   518  	for _, m := range modes {
   519  		testHandshakeReplay(t, config, numBlocks, m, true)
   520  	}
   521  }
   522  
   523  // Test mockProxyApp should not panic when app return ABCIResponses with some empty ResponseDeliverTx
   524  func TestMockProxyApp(t *testing.T) {
   525  	sim.CleanupFunc() //clean the test env created in TestSimulateValidatorsChange
   526  	logger := log.TestingLogger()
   527  	var validTxs, invalidTxs = 0, 0
   528  	txIndex := 0
   529  
   530  	assert.NotPanics(t, func() {
   531  		abciResWithEmptyDeliverTx := new(sm.ABCIResponses)
   532  		abciResWithEmptyDeliverTx.DeliverTx = make([]*abci.ResponseDeliverTx, 0)
   533  		abciResWithEmptyDeliverTx.DeliverTx = append(abciResWithEmptyDeliverTx.DeliverTx, &abci.ResponseDeliverTx{})
   534  
   535  		// called when saveABCIResponses:
   536  		bytes := cdc.MustMarshalBinaryBare(abciResWithEmptyDeliverTx)
   537  		loadedAbciRes := new(sm.ABCIResponses)
   538  
   539  		// this also happens sm.LoadABCIResponses
   540  		err := cdc.UnmarshalBinaryBare(bytes, loadedAbciRes)
   541  		require.NoError(t, err)
   542  
   543  		mock := newMockProxyApp([]byte("mock_hash"), loadedAbciRes)
   544  
   545  		abciRes := new(sm.ABCIResponses)
   546  		abciRes.DeliverTx = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTx))
   547  		// Execute transactions and get hash.
   548  		proxyCb := func(req *abci.Request, res *abci.Response) {
   549  			switch r := res.Value.(type) {
   550  			case *abci.Response_DeliverTx:
   551  				// TODO: make use of res.Log
   552  				// TODO: make use of this info
   553  				// Blocks may include invalid txs.
   554  				txRes := r.DeliverTx
   555  				if txRes.Code == abci.CodeTypeOK {
   556  					validTxs++
   557  				} else {
   558  					logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
   559  					invalidTxs++
   560  				}
   561  				abciRes.DeliverTx[txIndex] = txRes
   562  				txIndex++
   563  			}
   564  		}
   565  		mock.SetResponseCallback(proxyCb)
   566  
   567  		someTx := []byte("tx")
   568  		mock.DeliverTxAsync(abci.RequestDeliverTx{Tx: someTx})
   569  	})
   570  	assert.True(t, validTxs == 1)
   571  	assert.True(t, invalidTxs == 0)
   572  }
   573  
   574  func tempWALWithData(data []byte) string {
   575  	walFile, err := ioutil.TempFile("", "wal")
   576  	if err != nil {
   577  		panic(fmt.Sprintf("failed to create temp WAL file: %v", err))
   578  	}
   579  	_, err = walFile.Write(data)
   580  	if err != nil {
   581  		panic(fmt.Sprintf("failed to write to temp WAL file: %v", err))
   582  	}
   583  	if err := walFile.Close(); err != nil {
   584  		panic(fmt.Sprintf("failed to close temp WAL file: %v", err))
   585  	}
   586  	return walFile.Name()
   587  }
   588  
   589  // Make some blocks. Start a fresh app and apply nBlocks blocks. Then restart the app and sync it up with the remaining blocks
   590  func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uint, testValidatorsChange bool) {
   591  	var chain []*types.Block
   592  	var commits []*types.Commit
   593  	var store *mockBlockStore
   594  	var stateDB dbm.DB
   595  	var genisisState sm.State
   596  	if testValidatorsChange {
   597  		testConfig := ResetConfig(fmt.Sprintf("%s_%v_m", t.Name(), mode))
   598  		defer os.RemoveAll(testConfig.RootDir)
   599  		stateDB = dbm.NewMemDB()
   600  		genisisState = sim.GenesisState
   601  		config = sim.Config
   602  		chain = sim.Chain
   603  		commits = sim.Commits
   604  		store = newMockBlockStore(config, genisisState.ConsensusParams)
   605  	} else { //test single node
   606  		testConfig := ResetConfig(fmt.Sprintf("%s_%v_s", t.Name(), mode))
   607  		defer os.RemoveAll(testConfig.RootDir)
   608  		walBody, err := WALWithNBlocks(t, numBlocks)
   609  		require.NoError(t, err)
   610  		walFile := tempWALWithData(walBody)
   611  		config.Consensus.SetWalFile(walFile)
   612  
   613  		privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
   614  
   615  		wal, err := NewWAL(walFile)
   616  		require.NoError(t, err)
   617  		wal.SetLogger(log.TestingLogger())
   618  		err = wal.Start()
   619  		require.NoError(t, err)
   620  		defer wal.Stop()
   621  
   622  		chain, commits, err = makeBlockchainFromWAL(wal)
   623  		require.NoError(t, err)
   624  		stateDB, genisisState, store = stateAndStore(config, privVal.GetPubKey(), kvstore.ProtocolVersion)
   625  	}
   626  	store.chain = chain
   627  	store.commits = commits
   628  
   629  	state := genisisState.Copy()
   630  	// run the chain through state.ApplyBlock to build up the tendermint state
   631  	state = buildTMStateFromChain(config, stateDB, state, chain, nBlocks, mode)
   632  	latestAppHash := state.AppHash
   633  
   634  	// make a new client creator
   635  	kvstoreApp := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_a", nBlocks, mode)))
   636  
   637  	clientCreator2 := proxy.NewLocalClientCreator(kvstoreApp)
   638  	if nBlocks > 0 {
   639  		// run nBlocks against a new client to build up the app state.
   640  		// use a throwaway tendermint state
   641  		proxyApp := proxy.NewAppConns(clientCreator2)
   642  		stateDB1 := dbm.NewMemDB()
   643  		sm.SaveState(stateDB1, genisisState)
   644  		buildAppStateFromChain(proxyApp, stateDB1, genisisState, chain, nBlocks, mode)
   645  	}
   646  
   647  	// now start the app using the handshake - it should sync
   648  	genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
   649  	handshaker := NewHandshaker(stateDB, state, store, genDoc)
   650  	proxyApp := proxy.NewAppConns(clientCreator2)
   651  	if err := proxyApp.Start(); err != nil {
   652  		t.Fatalf("Error starting proxy app connections: %v", err)
   653  	}
   654  	defer proxyApp.Stop()
   655  	if err := handshaker.Handshake(proxyApp); err != nil {
   656  		t.Fatalf("Error on abci handshake: %v", err)
   657  	}
   658  
   659  	// get the latest app hash from the app
   660  	res, err := proxyApp.Query().InfoSync(abci.RequestInfo{Version: ""})
   661  	if err != nil {
   662  		t.Fatal(err)
   663  	}
   664  
   665  	// the app hash should be synced up
   666  	if !bytes.Equal(latestAppHash, res.LastBlockAppHash) {
   667  		t.Fatalf("Expected app hashes to match after handshake/replay. got %X, expected %X", res.LastBlockAppHash, latestAppHash)
   668  	}
   669  
   670  	expectedBlocksToSync := numBlocks - nBlocks
   671  	if nBlocks == numBlocks && mode > 0 {
   672  		expectedBlocksToSync++
   673  	} else if nBlocks > 0 && mode == 1 {
   674  		expectedBlocksToSync++
   675  	}
   676  
   677  	if handshaker.NBlocks() != expectedBlocksToSync {
   678  		t.Fatalf("Expected handshake to sync %d blocks, got %d", expectedBlocksToSync, handshaker.NBlocks())
   679  	}
   680  }
   681  
   682  func applyBlock(stateDB dbm.DB, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State {
   683  	testPartSize := types.BlockPartSizeBytes
   684  	blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
   685  
   686  	blkID := types.BlockID{Hash: blk.Hash(), PartsHeader: blk.MakePartSet(testPartSize).Header()}
   687  	newState, err := blockExec.ApplyBlock(st, blkID, blk)
   688  	if err != nil {
   689  		panic(err)
   690  	}
   691  	return newState
   692  }
   693  
   694  func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
   695  	state sm.State, chain []*types.Block, nBlocks int, mode uint) {
   696  	// start a new app without handshake, play nBlocks blocks
   697  	if err := proxyApp.Start(); err != nil {
   698  		panic(err)
   699  	}
   700  	defer proxyApp.Stop()
   701  
   702  	state.Version.Consensus.App = kvstore.ProtocolVersion //simulate handshake, receive app version
   703  	validators := types.TM2PB.ValidatorUpdates(state.Validators)
   704  	if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
   705  		Validators: validators,
   706  	}); err != nil {
   707  		panic(err)
   708  	}
   709  	sm.SaveState(stateDB, state) //save height 1's validatorsInfo
   710  
   711  	switch mode {
   712  	case 0:
   713  		for i := 0; i < nBlocks; i++ {
   714  			block := chain[i]
   715  			state = applyBlock(stateDB, state, block, proxyApp)
   716  		}
   717  	case 1, 2:
   718  		for i := 0; i < nBlocks-1; i++ {
   719  			block := chain[i]
   720  			state = applyBlock(stateDB, state, block, proxyApp)
   721  		}
   722  
   723  		if mode == 2 {
   724  			// update the kvstore height and apphash
   725  			// as if we ran commit but not
   726  			state = applyBlock(stateDB, state, chain[nBlocks-1], proxyApp)
   727  		}
   728  	}
   729  
   730  }
   731  
   732  func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, chain []*types.Block, nBlocks int, mode uint) sm.State {
   733  	// run the whole chain against this client to build up the tendermint state
   734  	clientCreator := proxy.NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))))
   735  	proxyApp := proxy.NewAppConns(clientCreator)
   736  	if err := proxyApp.Start(); err != nil {
   737  		panic(err)
   738  	}
   739  	defer proxyApp.Stop()
   740  
   741  	state.Version.Consensus.App = kvstore.ProtocolVersion //simulate handshake, receive app version
   742  	validators := types.TM2PB.ValidatorUpdates(state.Validators)
   743  	if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
   744  		Validators: validators,
   745  	}); err != nil {
   746  		panic(err)
   747  	}
   748  	sm.SaveState(stateDB, state) //save height 1's validatorsInfo
   749  
   750  	switch mode {
   751  	case 0:
   752  		// sync right up
   753  		for _, block := range chain {
   754  			state = applyBlock(stateDB, state, block, proxyApp)
   755  		}
   756  
   757  	case 1, 2:
   758  		// sync up to the penultimate as if we stored the block.
   759  		// whether we commit or not depends on the appHash
   760  		for _, block := range chain[:len(chain)-1] {
   761  			state = applyBlock(stateDB, state, block, proxyApp)
   762  		}
   763  
   764  		// apply the final block to a state copy so we can
   765  		// get the right next appHash but keep the state back
   766  		applyBlock(stateDB, state, chain[len(chain)-1], proxyApp)
   767  	}
   768  
   769  	return state
   770  }
   771  
   772  func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
   773  	// 1. Initialize tendermint and commit 3 blocks with the following app hashes:
   774  	//		- 0x01
   775  	//		- 0x02
   776  	//		- 0x03
   777  	config := ResetConfig("handshake_test_")
   778  	defer os.RemoveAll(config.RootDir)
   779  	privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
   780  	const appVersion = 0x0
   781  	stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), appVersion)
   782  	genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
   783  	state.LastValidators = state.Validators.Copy()
   784  	// mode = 0 for committing all the blocks
   785  	blocks := makeBlocks(3, &state, privVal)
   786  	store.chain = blocks
   787  
   788  	// 2. Tendermint must panic if app returns wrong hash for the first block
   789  	//		- RANDOM HASH
   790  	//		- 0x02
   791  	//		- 0x03
   792  	{
   793  		app := &badApp{numBlocks: 3, allHashesAreWrong: true}
   794  		clientCreator := proxy.NewLocalClientCreator(app)
   795  		proxyApp := proxy.NewAppConns(clientCreator)
   796  		err := proxyApp.Start()
   797  		require.NoError(t, err)
   798  		defer proxyApp.Stop()
   799  
   800  		assert.Panics(t, func() {
   801  			h := NewHandshaker(stateDB, state, store, genDoc)
   802  			h.Handshake(proxyApp)
   803  		})
   804  	}
   805  
   806  	// 3. Tendermint must panic if app returns wrong hash for the last block
   807  	//		- 0x01
   808  	//		- 0x02
   809  	//		- RANDOM HASH
   810  	{
   811  		app := &badApp{numBlocks: 3, onlyLastHashIsWrong: true}
   812  		clientCreator := proxy.NewLocalClientCreator(app)
   813  		proxyApp := proxy.NewAppConns(clientCreator)
   814  		err := proxyApp.Start()
   815  		require.NoError(t, err)
   816  		defer proxyApp.Stop()
   817  
   818  		assert.Panics(t, func() {
   819  			h := NewHandshaker(stateDB, state, store, genDoc)
   820  			h.Handshake(proxyApp)
   821  		})
   822  	}
   823  }
   824  
   825  func makeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Block {
   826  	blocks := make([]*types.Block, 0)
   827  
   828  	var (
   829  		prevBlock     *types.Block
   830  		prevBlockMeta *types.BlockMeta
   831  	)
   832  
   833  	appHeight := byte(0x01)
   834  	for i := 0; i < n; i++ {
   835  		height := int64(i + 1)
   836  
   837  		block, parts := makeBlock(*state, prevBlock, prevBlockMeta, privVal, height)
   838  		blocks = append(blocks, block)
   839  
   840  		prevBlock = block
   841  		prevBlockMeta = types.NewBlockMeta(block, parts)
   842  
   843  		// update state
   844  		state.AppHash = []byte{appHeight}
   845  		appHeight++
   846  		state.LastBlockHeight = height
   847  	}
   848  
   849  	return blocks
   850  }
   851  
   852  func makeVote(header *types.Header, blockID types.BlockID, valset *types.ValidatorSet, privVal types.PrivValidator) *types.Vote {
   853  	addr := privVal.GetPubKey().Address()
   854  	idx, _ := valset.GetByAddress(addr)
   855  	vote := &types.Vote{
   856  		ValidatorAddress: addr,
   857  		ValidatorIndex:   idx,
   858  		Height:           header.Height,
   859  		Round:            1,
   860  		Timestamp:        tmtime.Now(),
   861  		Type:             types.PrecommitType,
   862  		BlockID:          blockID,
   863  	}
   864  
   865  	privVal.SignVote(header.ChainID, vote)
   866  
   867  	return vote
   868  }
   869  
   870  func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.BlockMeta,
   871  	privVal types.PrivValidator, height int64) (*types.Block, *types.PartSet) {
   872  
   873  	lastCommit := types.NewCommit(types.BlockID{}, nil)
   874  	if height > 1 {
   875  		vote := makeVote(&lastBlock.Header, lastBlockMeta.BlockID, state.Validators, privVal).CommitSig()
   876  		lastCommit = types.NewCommit(lastBlockMeta.BlockID, []*types.CommitSig{vote})
   877  	}
   878  
   879  	return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address)
   880  }
   881  
   882  type badApp struct {
   883  	abci.BaseApplication
   884  	numBlocks           byte
   885  	height              byte
   886  	allHashesAreWrong   bool
   887  	onlyLastHashIsWrong bool
   888  }
   889  
   890  func (app *badApp) Commit() abci.ResponseCommit {
   891  	app.height++
   892  	if app.onlyLastHashIsWrong {
   893  		if app.height == app.numBlocks {
   894  			return abci.ResponseCommit{Data: cmn.RandBytes(8)}
   895  		}
   896  		return abci.ResponseCommit{Data: []byte{app.height}}
   897  	} else if app.allHashesAreWrong {
   898  		return abci.ResponseCommit{Data: cmn.RandBytes(8)}
   899  	}
   900  
   901  	panic("either allHashesAreWrong or onlyLastHashIsWrong must be set")
   902  }
   903  
   904  //--------------------------
   905  // utils for making blocks
   906  
   907  func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
   908  	var height int64
   909  
   910  	// Search for height marker
   911  	gr, found, err := wal.SearchForEndHeight(height, &WALSearchOptions{})
   912  	if err != nil {
   913  		return nil, nil, err
   914  	}
   915  	if !found {
   916  		return nil, nil, fmt.Errorf("WAL does not contain height %d", height)
   917  	}
   918  	defer gr.Close() // nolint: errcheck
   919  
   920  	// log.Notice("Build a blockchain by reading from the WAL")
   921  
   922  	var (
   923  		blocks          []*types.Block
   924  		commits         []*types.Commit
   925  		thisBlockParts  *types.PartSet
   926  		thisBlockCommit *types.Commit
   927  	)
   928  
   929  	dec := NewWALDecoder(gr)
   930  	for {
   931  		msg, err := dec.Decode()
   932  		if err == io.EOF {
   933  			break
   934  		} else if err != nil {
   935  			return nil, nil, err
   936  		}
   937  
   938  		piece := readPieceFromWAL(msg)
   939  		if piece == nil {
   940  			continue
   941  		}
   942  
   943  		switch p := piece.(type) {
   944  		case EndHeightMessage:
   945  			// if its not the first one, we have a full block
   946  			if thisBlockParts != nil {
   947  				var block = new(types.Block)
   948  				_, err = cdc.UnmarshalBinaryLengthPrefixedReader(thisBlockParts.GetReader(), block, 0)
   949  				if err != nil {
   950  					panic(err)
   951  				}
   952  				if block.Height != height+1 {
   953  					panic(fmt.Sprintf("read bad block from wal. got height %d, expected %d", block.Height, height+1))
   954  				}
   955  				commitHeight := thisBlockCommit.Precommits[0].Height
   956  				if commitHeight != height+1 {
   957  					panic(fmt.Sprintf("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
   958  				}
   959  				blocks = append(blocks, block)
   960  				commits = append(commits, thisBlockCommit)
   961  				height++
   962  			}
   963  		case *types.PartSetHeader:
   964  			thisBlockParts = types.NewPartSetFromHeader(*p)
   965  		case *types.Part:
   966  			_, err := thisBlockParts.AddPart(p)
   967  			if err != nil {
   968  				return nil, nil, err
   969  			}
   970  		case *types.Vote:
   971  			if p.Type == types.PrecommitType {
   972  				commitSigs := []*types.CommitSig{p.CommitSig()}
   973  				thisBlockCommit = types.NewCommit(p.BlockID, commitSigs)
   974  			}
   975  		}
   976  	}
   977  	// grab the last block too
   978  	var block = new(types.Block)
   979  	_, err = cdc.UnmarshalBinaryLengthPrefixedReader(thisBlockParts.GetReader(), block, 0)
   980  	if err != nil {
   981  		panic(err)
   982  	}
   983  	if block.Height != height+1 {
   984  		panic(fmt.Sprintf("read bad block from wal. got height %d, expected %d", block.Height, height+1))
   985  	}
   986  	commitHeight := thisBlockCommit.Precommits[0].Height
   987  	if commitHeight != height+1 {
   988  		panic(fmt.Sprintf("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
   989  	}
   990  	blocks = append(blocks, block)
   991  	commits = append(commits, thisBlockCommit)
   992  	return blocks, commits, nil
   993  }
   994  
   995  func readPieceFromWAL(msg *TimedWALMessage) interface{} {
   996  	// for logging
   997  	switch m := msg.Msg.(type) {
   998  	case msgInfo:
   999  		switch msg := m.Msg.(type) {
  1000  		case *ProposalMessage:
  1001  			return &msg.Proposal.BlockID.PartsHeader
  1002  		case *BlockPartMessage:
  1003  			return msg.Part
  1004  		case *VoteMessage:
  1005  			return msg.Vote
  1006  		}
  1007  	case EndHeightMessage:
  1008  		return m
  1009  	}
  1010  
  1011  	return nil
  1012  }
  1013  
  1014  // fresh state and mock store
  1015  func stateAndStore(config *cfg.Config, pubKey crypto.PubKey, appVersion version.Protocol) (dbm.DB, sm.State, *mockBlockStore) {
  1016  	stateDB := dbm.NewMemDB()
  1017  	state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile())
  1018  	state.Version.Consensus.App = appVersion
  1019  	store := newMockBlockStore(config, state.ConsensusParams)
  1020  	sm.SaveState(stateDB, state)
  1021  	return stateDB, state, store
  1022  }
  1023  
  1024  //----------------------------------
  1025  // mock block store
  1026  
  1027  type mockBlockStore struct {
  1028  	config  *cfg.Config
  1029  	params  types.ConsensusParams
  1030  	chain   []*types.Block
  1031  	commits []*types.Commit
  1032  }
  1033  
  1034  // TODO: NewBlockStore(db.NewMemDB) ...
  1035  func newMockBlockStore(config *cfg.Config, params types.ConsensusParams) *mockBlockStore {
  1036  	return &mockBlockStore{config, params, nil, nil}
  1037  }
  1038  
  1039  func (bs *mockBlockStore) Height() int64                       { return int64(len(bs.chain)) }
  1040  func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain[height-1] }
  1041  func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
  1042  	block := bs.chain[height-1]
  1043  	return &types.BlockMeta{
  1044  		BlockID: types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(types.BlockPartSizeBytes).Header()},
  1045  		Header:  block.Header,
  1046  	}
  1047  }
  1048  func (bs *mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
  1049  func (bs *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
  1050  }
  1051  func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
  1052  	return bs.commits[height-1]
  1053  }
  1054  func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
  1055  	return bs.commits[height-1]
  1056  }
  1057  
  1058  //---------------------------------------
  1059  // Test handshake/init chain
  1060  
  1061  func TestHandshakeUpdatesValidators(t *testing.T) {
  1062  	val, _ := types.RandValidator(true, 10)
  1063  	vals := types.NewValidatorSet([]*types.Validator{val})
  1064  	app := &initChainApp{vals: types.TM2PB.ValidatorUpdates(vals)}
  1065  	clientCreator := proxy.NewLocalClientCreator(app)
  1066  
  1067  	config := ResetConfig("handshake_test_")
  1068  	defer os.RemoveAll(config.RootDir)
  1069  	privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
  1070  	stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), 0x0)
  1071  
  1072  	oldValAddr := state.Validators.Validators[0].Address
  1073  
  1074  	// now start the app using the handshake - it should sync
  1075  	genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
  1076  	handshaker := NewHandshaker(stateDB, state, store, genDoc)
  1077  	proxyApp := proxy.NewAppConns(clientCreator)
  1078  	if err := proxyApp.Start(); err != nil {
  1079  		t.Fatalf("Error starting proxy app connections: %v", err)
  1080  	}
  1081  	defer proxyApp.Stop()
  1082  	if err := handshaker.Handshake(proxyApp); err != nil {
  1083  		t.Fatalf("Error on abci handshake: %v", err)
  1084  	}
  1085  
  1086  	// reload the state, check the validator set was updated
  1087  	state = sm.LoadState(stateDB)
  1088  
  1089  	newValAddr := state.Validators.Validators[0].Address
  1090  	expectValAddr := val.Address
  1091  	assert.NotEqual(t, oldValAddr, newValAddr)
  1092  	assert.Equal(t, newValAddr, expectValAddr)
  1093  }
  1094  
  1095  // returns the vals on InitChain
  1096  type initChainApp struct {
  1097  	abci.BaseApplication
  1098  	vals []abci.ValidatorUpdate
  1099  }
  1100  
  1101  func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
  1102  	return abci.ResponseInitChain{
  1103  		Validators: ica.vals,
  1104  	}
  1105  }