github.com/PikeEcosystem/tendermint@v0.0.4/state/execution_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/mock"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    14  	tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
    15  
    16  	"github.com/PikeEcosystem/tendermint/crypto"
    17  	"github.com/PikeEcosystem/tendermint/crypto/ed25519"
    18  	cryptoenc "github.com/PikeEcosystem/tendermint/crypto/encoding"
    19  	"github.com/PikeEcosystem/tendermint/crypto/tmhash"
    20  	"github.com/PikeEcosystem/tendermint/libs/bytes"
    21  	"github.com/PikeEcosystem/tendermint/libs/log"
    22  	mmock "github.com/PikeEcosystem/tendermint/mempool/mock"
    23  	"github.com/PikeEcosystem/tendermint/proxy"
    24  	sm "github.com/PikeEcosystem/tendermint/state"
    25  	"github.com/PikeEcosystem/tendermint/state/mocks"
    26  	"github.com/PikeEcosystem/tendermint/types"
    27  	tmtime "github.com/PikeEcosystem/tendermint/types/time"
    28  	"github.com/PikeEcosystem/tendermint/version"
    29  )
    30  
    31  var (
    32  	chainID             = "execution_chain"
    33  	testPartSize uint32 = 65536
    34  	nTxsPerBlock        = 10
    35  )
    36  
    37  func TestApplyBlock(t *testing.T) {
    38  	app := &testApp{}
    39  	cc := proxy.NewLocalClientCreator(app)
    40  	proxyApp := proxy.NewAppConns(cc)
    41  	err := proxyApp.Start()
    42  	require.Nil(t, err)
    43  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
    44  
    45  	state, stateDB, privVals := makeState(1, 1)
    46  	stateStore := sm.NewStore(stateDB)
    47  
    48  	blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
    49  		mmock.Mempool{}, sm.EmptyEvidencePool{})
    50  
    51  	block := makeBlockWithPrivVal(state, privVals[state.Validators.Validators[0].Address.String()], 1)
    52  	blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
    53  
    54  	state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block, nil)
    55  	require.Nil(t, err)
    56  	assert.EqualValues(t, retainHeight, 1)
    57  
    58  	// TODO check state and mempool
    59  	assert.EqualValues(t, TestAppVersion, state.Version.Consensus.App, "App version wasn't updated")
    60  }
    61  
    62  // TestBeginBlockValidators ensures we send absent validators list.
    63  func TestBeginBlockValidators(t *testing.T) {
    64  	app := &testApp{}
    65  	cc := proxy.NewLocalClientCreator(app)
    66  	proxyApp := proxy.NewAppConns(cc)
    67  	err := proxyApp.Start()
    68  	require.Nil(t, err)
    69  	defer proxyApp.Stop() //nolint:errcheck // no need to check error again
    70  
    71  	state, stateDB, privVals := makeState(2, 2)
    72  	stateStore := sm.NewStore(stateDB)
    73  
    74  	prevHash := state.LastBlockID.Hash
    75  	prevParts := types.PartSetHeader{}
    76  	prevBlockID := types.BlockID{Hash: prevHash, PartSetHeader: prevParts}
    77  
    78  	var (
    79  		now        = tmtime.Now()
    80  		commitSig0 = types.NewCommitSigForBlock(
    81  			[]byte("Signature1"),
    82  			state.Validators.Validators[0].Address,
    83  			now)
    84  		commitSig1 = types.NewCommitSigForBlock(
    85  			[]byte("Signature2"),
    86  			state.Validators.Validators[1].Address,
    87  			now)
    88  		absentSig = types.NewCommitSigAbsent()
    89  	)
    90  
    91  	testCases := []struct {
    92  		desc                     string
    93  		lastCommitSigs           []types.CommitSig
    94  		expectedAbsentValidators []int
    95  	}{
    96  		{"none absent", []types.CommitSig{commitSig0, commitSig1}, []int{}},
    97  		{"one absent", []types.CommitSig{commitSig0, absentSig}, []int{1}},
    98  		{"multiple absent", []types.CommitSig{absentSig, absentSig}, []int{0, 1}},
    99  	}
   100  
   101  	for _, tc := range testCases {
   102  		lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs)
   103  
   104  		proposer := state.Validators.SelectProposer(state.LastProofHash, 1, 0)
   105  		message := state.MakeHashMessage(0)
   106  		proof, _ := privVals[proposer.Address.String()].GenerateVRFProof(message)
   107  
   108  		// block for height 2
   109  		block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, proposer.Address, 0, proof)
   110  
   111  		_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 1)
   112  		require.Nil(t, err, tc.desc)
   113  
   114  		// -> app receives a list of validators with a bool indicating if they signed
   115  		ctr := 0
   116  		for i, v := range app.CommitVotes {
   117  			if ctr < len(tc.expectedAbsentValidators) &&
   118  				tc.expectedAbsentValidators[ctr] == i {
   119  
   120  				assert.False(t, v.SignedLastBlock)
   121  				ctr++
   122  			} else {
   123  				assert.True(t, v.SignedLastBlock)
   124  			}
   125  		}
   126  	}
   127  }
   128  
   129  // TestBeginBlockByzantineValidators ensures we send byzantine validators list.
   130  func TestBeginBlockByzantineValidators(t *testing.T) {
   131  	app := &testApp{}
   132  	cc := proxy.NewLocalClientCreator(app)
   133  	proxyApp := proxy.NewAppConns(cc)
   134  	err := proxyApp.Start()
   135  	require.Nil(t, err)
   136  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   137  
   138  	state, stateDB, privVals := makeState(2, 12)
   139  	stateStore := sm.NewStore(stateDB)
   140  
   141  	defaultEvidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
   142  	privVal := privVals[state.Validators.Validators[0].Address.String()]
   143  	blockID := makeBlockID([]byte("headerhash"), 1000, []byte("partshash"))
   144  	header := &types.Header{
   145  		Version:            tmversion.Consensus{Block: version.BlockProtocol, App: version.AppProtocol},
   146  		ChainID:            state.ChainID,
   147  		Height:             10,
   148  		Time:               defaultEvidenceTime,
   149  		LastBlockID:        blockID,
   150  		LastCommitHash:     crypto.CRandBytes(tmhash.Size),
   151  		DataHash:           crypto.CRandBytes(tmhash.Size),
   152  		ValidatorsHash:     state.Validators.Hash(),
   153  		NextValidatorsHash: state.Validators.Hash(),
   154  		ConsensusHash:      crypto.CRandBytes(tmhash.Size),
   155  		AppHash:            crypto.CRandBytes(tmhash.Size),
   156  		LastResultsHash:    crypto.CRandBytes(tmhash.Size),
   157  		EvidenceHash:       crypto.CRandBytes(tmhash.Size),
   158  		ProposerAddress:    crypto.CRandBytes(crypto.AddressSize),
   159  	}
   160  
   161  	// we don't need to worry about validating the evidence as long as they pass validate basic
   162  	dve := types.NewMockDuplicateVoteEvidenceWithValidator(3, defaultEvidenceTime, privVal, state.ChainID)
   163  	dve.ValidatorPower = 1000
   164  	lcae := &types.LightClientAttackEvidence{
   165  		ConflictingBlock: &types.LightBlock{
   166  			SignedHeader: &types.SignedHeader{
   167  				Header: header,
   168  				Commit: types.NewCommit(10, 0, makeBlockID(header.Hash(), 100, []byte("partshash")), []types.CommitSig{{
   169  					BlockIDFlag:      types.BlockIDFlagNil,
   170  					ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
   171  					Timestamp:        defaultEvidenceTime,
   172  					Signature:        crypto.CRandBytes(types.MaxSignatureSize),
   173  				}}),
   174  			},
   175  			ValidatorSet: state.Validators,
   176  		},
   177  		CommonHeight:        8,
   178  		ByzantineValidators: []*types.Validator{state.Validators.Validators[0]},
   179  		TotalVotingPower:    12,
   180  		Timestamp:           defaultEvidenceTime,
   181  	}
   182  
   183  	ev := []types.Evidence{dve, lcae}
   184  
   185  	abciEv := []abci.Evidence{
   186  		{
   187  			Type:             abci.EvidenceType_DUPLICATE_VOTE,
   188  			Height:           3,
   189  			Time:             defaultEvidenceTime,
   190  			Validator:        types.OC2PB.Validator(state.Validators.Validators[0]),
   191  			TotalVotingPower: 10,
   192  		},
   193  		{
   194  			Type:             abci.EvidenceType_LIGHT_CLIENT_ATTACK,
   195  			Height:           8,
   196  			Time:             defaultEvidenceTime,
   197  			Validator:        types.OC2PB.Validator(state.Validators.Validators[0]),
   198  			TotalVotingPower: 12,
   199  		},
   200  	}
   201  
   202  	evpool := &mocks.EvidencePool{}
   203  	evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return(ev, int64(100))
   204  	evpool.On("Update", mock.AnythingOfType("state.State"), mock.AnythingOfType("types.EvidenceList")).Return()
   205  	evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
   206  
   207  	blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
   208  		mmock.Mempool{}, evpool)
   209  
   210  	now := tmtime.Now()
   211  	state.LastBlockID = blockID
   212  	state.LastBlockTime = now.Add(-1 * time.Second)
   213  
   214  	prevHash := state.LastBlockID.Hash
   215  	prevParts := types.PartSetHeader{}
   216  	prevBlockID := types.BlockID{Hash: prevHash, PartSetHeader: prevParts}
   217  
   218  	ev1 := types.DuplicateVoteEvidence{
   219  		VoteA:            &types.Vote{},
   220  		VoteB:            &types.Vote{},
   221  		TotalVotingPower: 100,
   222  		ValidatorPower:   10,
   223  		Timestamp:        time.Now(),
   224  	}
   225  	ev2 := types.LightClientAttackEvidence{}
   226  
   227  	testCases := []struct {
   228  		desc                        string
   229  		evidence                    []types.Evidence
   230  		expectedByzantineValidators []abci.Evidence
   231  	}{
   232  		{"none byzantine", []types.Evidence{}, []abci.Evidence{}},
   233  		{"one byzantine", []types.Evidence{&ev1}, ev1.ABCI()},
   234  		{"multiple byzantine", []types.Evidence{&ev1, &ev2}, append(ev1.ABCI(), ev2.ABCI()...)},
   235  	}
   236  
   237  	var (
   238  		commitSig0 = types.NewCommitSigForBlock(
   239  			[]byte("Signature1"),
   240  			state.Validators.Validators[0].Address,
   241  			now)
   242  		commitSig1 = types.NewCommitSigForBlock(
   243  			[]byte("Signature2"),
   244  			state.Validators.Validators[1].Address,
   245  			now)
   246  	)
   247  	commitSigs := []types.CommitSig{commitSig0, commitSig1}
   248  	lastCommit := types.NewCommit(9, 0, prevBlockID, commitSigs)
   249  	for _, tc := range testCases {
   250  		message := state.MakeHashMessage(0)
   251  		proposer := state.Validators.SelectProposer(state.LastProofHash, 1, 0)
   252  		proof, _ := privVals[proposer.Address.String()].GenerateVRFProof(message)
   253  		block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, proposer.Address, 0, proof)
   254  		block.Time = now
   255  		block.Evidence.Evidence = tc.evidence
   256  		_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 10)
   257  		require.Nil(t, err, tc.desc)
   258  	}
   259  
   260  	proposer := state.Validators.SelectProposer(state.LastProofHash, 12, 0)
   261  	privVal = privVals[proposer.Address.String()]
   262  
   263  	block := makeBlockWithPrivVal(state, privVal, 12)
   264  	block.Evidence = types.EvidenceData{Evidence: ev}
   265  	block.Header.EvidenceHash = block.Evidence.Hash()
   266  	blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
   267  	block.LastCommit, _ = makeValidCommit(11, state.LastBlockID, state.Validators, privVals)
   268  	block.LastCommitHash = block.LastCommit.Hash()
   269  	block.Time = sm.MedianTime(block.LastCommit, state.LastValidators)
   270  	message := state.MakeHashMessage(block.Round)
   271  	proof, _ := privVal.GenerateVRFProof(message)
   272  	block.Proof = bytes.HexBytes(proof)
   273  
   274  	state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block, nil)
   275  	require.Nil(t, err)
   276  	assert.EqualValues(t, retainHeight, 1)
   277  
   278  	// TODO check state and mempool
   279  	assert.Equal(t, abciEv, app.ByzantineValidators)
   280  }
   281  
   282  func TestValidateValidatorUpdates(t *testing.T) {
   283  	pubkey1 := ed25519.GenPrivKey().PubKey()
   284  	pubkey2 := ed25519.GenPrivKey().PubKey()
   285  	pk1, err := cryptoenc.PubKeyToProto(pubkey1)
   286  	assert.NoError(t, err)
   287  	pk2, err := cryptoenc.PubKeyToProto(pubkey2)
   288  	assert.NoError(t, err)
   289  
   290  	defaultValidatorParams := tmproto.ValidatorParams{PubKeyTypes: []string{types.ABCIPubKeyTypeEd25519}}
   291  
   292  	testCases := []struct {
   293  		name string
   294  
   295  		abciUpdates     []abci.ValidatorUpdate
   296  		validatorParams tmproto.ValidatorParams
   297  
   298  		shouldErr bool
   299  	}{
   300  		{
   301  			"adding a validator is OK",
   302  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: 20}},
   303  			defaultValidatorParams,
   304  			false,
   305  		},
   306  		{
   307  			"updating a validator is OK",
   308  			[]abci.ValidatorUpdate{{PubKey: pk1, Power: 20}},
   309  			defaultValidatorParams,
   310  			false,
   311  		},
   312  		{
   313  			"removing a validator is OK",
   314  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
   315  			defaultValidatorParams,
   316  			false,
   317  		},
   318  		{
   319  			"adding a validator with negative power results in error",
   320  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: -100}},
   321  			defaultValidatorParams,
   322  			true,
   323  		},
   324  	}
   325  
   326  	for _, tc := range testCases {
   327  		tc := tc
   328  		t.Run(tc.name, func(t *testing.T) {
   329  			err := sm.ValidateValidatorUpdates(tc.abciUpdates, tc.validatorParams)
   330  			if tc.shouldErr {
   331  				assert.Error(t, err)
   332  			} else {
   333  				assert.NoError(t, err)
   334  			}
   335  		})
   336  	}
   337  }
   338  
   339  func TestUpdateValidators(t *testing.T) {
   340  	pubkey1 := ed25519.GenPrivKey().PubKey()
   341  	val1 := types.NewValidator(pubkey1, 10)
   342  	pubkey2 := ed25519.GenPrivKey().PubKey()
   343  	val2 := types.NewValidator(pubkey2, 20)
   344  
   345  	pk, err := cryptoenc.PubKeyToProto(pubkey1)
   346  	require.NoError(t, err)
   347  	pk2, err := cryptoenc.PubKeyToProto(pubkey2)
   348  	require.NoError(t, err)
   349  
   350  	testCases := []struct {
   351  		name string
   352  
   353  		currentSet  *types.ValidatorSet
   354  		abciUpdates []abci.ValidatorUpdate
   355  
   356  		resultingSet *types.ValidatorSet
   357  		shouldErr    bool
   358  	}{
   359  		{
   360  			"adding a validator is OK",
   361  			types.NewValidatorSet([]*types.Validator{val1}),
   362  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: 20}},
   363  			types.NewValidatorSet([]*types.Validator{val1, val2}),
   364  			false,
   365  		},
   366  		{
   367  			"updating a validator is OK",
   368  			types.NewValidatorSet([]*types.Validator{val1}),
   369  			[]abci.ValidatorUpdate{{PubKey: pk, Power: 20}},
   370  			types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
   371  			false,
   372  		},
   373  		{
   374  			"removing a validator is OK",
   375  			types.NewValidatorSet([]*types.Validator{val1, val2}),
   376  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
   377  			types.NewValidatorSet([]*types.Validator{val1}),
   378  			false,
   379  		},
   380  		{
   381  			"removing a non-existing validator results in error",
   382  			types.NewValidatorSet([]*types.Validator{val1}),
   383  			[]abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
   384  			types.NewValidatorSet([]*types.Validator{val1}),
   385  			true,
   386  		},
   387  	}
   388  
   389  	for _, tc := range testCases {
   390  		tc := tc
   391  		t.Run(tc.name, func(t *testing.T) {
   392  			updates, err := types.PB2OC.ValidatorUpdates(tc.abciUpdates)
   393  			assert.NoError(t, err)
   394  			err = tc.currentSet.UpdateWithChangeSet(updates)
   395  			if tc.shouldErr {
   396  				assert.Error(t, err)
   397  			} else {
   398  				assert.NoError(t, err)
   399  				require.Equal(t, tc.resultingSet.Size(), tc.currentSet.Size())
   400  
   401  				assert.Equal(t, tc.resultingSet.TotalVotingPower(), tc.currentSet.TotalVotingPower())
   402  
   403  				assert.Equal(t, tc.resultingSet.Validators[0].Address, tc.currentSet.Validators[0].Address)
   404  				if tc.resultingSet.Size() > 1 {
   405  					assert.Equal(t, tc.resultingSet.Validators[1].Address, tc.currentSet.Validators[1].Address)
   406  				}
   407  			}
   408  		})
   409  	}
   410  }
   411  
   412  // TestEndBlockValidatorUpdates ensures we update validator set and send an event.
   413  func TestEndBlockValidatorUpdates(t *testing.T) {
   414  	app := &testApp{}
   415  	cc := proxy.NewLocalClientCreator(app)
   416  	proxyApp := proxy.NewAppConns(cc)
   417  	err := proxyApp.Start()
   418  	require.Nil(t, err)
   419  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   420  
   421  	state, stateDB, privVals := makeState(1, 1)
   422  	stateStore := sm.NewStore(stateDB)
   423  
   424  	blockExec := sm.NewBlockExecutor(
   425  		stateStore,
   426  		log.TestingLogger(),
   427  		proxyApp.Consensus(),
   428  		mmock.Mempool{},
   429  		sm.EmptyEvidencePool{},
   430  	)
   431  
   432  	eventBus := types.NewEventBus()
   433  	err = eventBus.Start()
   434  	require.NoError(t, err)
   435  	defer eventBus.Stop() //nolint:errcheck // ignore for tests
   436  
   437  	blockExec.SetEventBus(eventBus)
   438  
   439  	updatesSub, err := eventBus.Subscribe(
   440  		context.Background(),
   441  		"TestEndBlockValidatorUpdates",
   442  		types.EventQueryValidatorSetUpdates,
   443  	)
   444  	require.NoError(t, err)
   445  
   446  	block := makeBlockWithPrivVal(state, privVals[state.Validators.Validators[0].Address.String()], 1)
   447  	blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
   448  
   449  	pubkey := ed25519.GenPrivKey().PubKey()
   450  	pk, err := cryptoenc.PubKeyToProto(pubkey)
   451  	require.NoError(t, err)
   452  	app.ValidatorUpdates = []abci.ValidatorUpdate{
   453  		{PubKey: pk, Power: 10},
   454  	}
   455  
   456  	state, _, err = blockExec.ApplyBlock(state, blockID, block, nil)
   457  	require.Nil(t, err)
   458  	// test new validator was added to NextValidators
   459  	if assert.Equal(t, state.Validators.Size()+1, state.NextValidators.Size()) {
   460  		idx, _ := state.NextValidators.GetByAddress(pubkey.Address())
   461  		if idx < 0 {
   462  			t.Fatalf("can't find address %v in the set %v", pubkey.Address(), state.NextValidators)
   463  		}
   464  	}
   465  
   466  	// test we threw an event
   467  	select {
   468  	case msg := <-updatesSub.Out():
   469  		event, ok := msg.Data().(types.EventDataValidatorSetUpdates)
   470  		require.True(t, ok, "Expected event of type EventDataValidatorSetUpdates, got %T", msg.Data())
   471  		if assert.NotEmpty(t, event.ValidatorUpdates) {
   472  			assert.Equal(t, pubkey, event.ValidatorUpdates[0].PubKey)
   473  			assert.EqualValues(t, 10, event.ValidatorUpdates[0].VotingPower)
   474  		}
   475  	case <-updatesSub.Cancelled():
   476  		t.Fatalf("updatesSub was cancelled (reason: %v)", updatesSub.Err())
   477  	case <-time.After(1 * time.Second):
   478  		t.Fatal("Did not receive EventValidatorSetUpdates within 1 sec.")
   479  	}
   480  }
   481  
   482  // TestEndBlockValidatorUpdatesResultingInEmptySet checks that processing validator updates that
   483  // would result in empty set causes no panic, an error is raised and NextValidators is not updated
   484  func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
   485  	app := &testApp{}
   486  	cc := proxy.NewLocalClientCreator(app)
   487  	proxyApp := proxy.NewAppConns(cc)
   488  	err := proxyApp.Start()
   489  	require.Nil(t, err)
   490  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   491  
   492  	state, stateDB, _ := makeState(1, 1)
   493  	stateStore := sm.NewStore(stateDB)
   494  	blockExec := sm.NewBlockExecutor(
   495  		stateStore,
   496  		log.TestingLogger(),
   497  		proxyApp.Consensus(),
   498  		mmock.Mempool{},
   499  		sm.EmptyEvidencePool{},
   500  	)
   501  
   502  	block := makeBlock(state, 1)
   503  	blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
   504  
   505  	vp, err := cryptoenc.PubKeyToProto(state.Validators.Validators[0].PubKey)
   506  	require.NoError(t, err)
   507  	// Remove the only validator
   508  	app.ValidatorUpdates = []abci.ValidatorUpdate{
   509  		{PubKey: vp, Power: 0},
   510  	}
   511  
   512  	assert.NotPanics(t, func() { state, _, err = blockExec.ApplyBlock(state, blockID, block, nil) })
   513  	assert.NotNil(t, err)
   514  	assert.NotEmpty(t, state.NextValidators.Validators)
   515  }
   516  
   517  func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID {
   518  	var (
   519  		h   = make([]byte, tmhash.Size)
   520  		psH = make([]byte, tmhash.Size)
   521  	)
   522  	copy(h, hash)
   523  	copy(psH, partSetHash)
   524  	return types.BlockID{
   525  		Hash: h,
   526  		PartSetHeader: types.PartSetHeader{
   527  			Total: partSetSize,
   528  			Hash:  psH,
   529  		},
   530  	}
   531  }