|
package evidence
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
dbm "github.com/tendermint/tm-db"
|
|
|
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
|
"github.com/tendermint/tendermint/libs/bytes"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
tmrand "github.com/tendermint/tendermint/libs/rand"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
sm "github.com/tendermint/tendermint/state"
|
|
"github.com/tendermint/tendermint/store"
|
|
"github.com/tendermint/tendermint/types"
|
|
tmtime "github.com/tendermint/tendermint/types/time"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
code := m.Run()
|
|
os.Exit(code)
|
|
}
|
|
|
|
const evidenceChainID = "test_chain"
|
|
|
|
func TestEvidencePool(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
valAddr = val.PrivKey.PubKey().Address()
|
|
height = int64(52)
|
|
stateDB = initializeValidatorState(val, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
goodEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(height, evidenceTime, val, evidenceChainID)
|
|
badEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(1, evidenceTime, val, evidenceChainID)
|
|
)
|
|
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
// bad evidence
|
|
err = pool.AddEvidence(badEvidence)
|
|
if assert.Error(t, err) {
|
|
assert.Contains(t, err.Error(), "is too old; min height is 32 and evidence can not be older than")
|
|
}
|
|
assert.False(t, pool.IsPending(badEvidence))
|
|
assert.True(t, pool.IsEvidenceExpired(badEvidence))
|
|
|
|
// good evidence
|
|
evAdded := make(chan struct{})
|
|
go func() {
|
|
<-pool.EvidenceWaitChan()
|
|
close(evAdded)
|
|
}()
|
|
|
|
err = pool.AddEvidence(goodEvidence)
|
|
require.NoError(t, err)
|
|
|
|
select {
|
|
case <-evAdded:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("evidence was not added to list after 5s")
|
|
}
|
|
|
|
assert.Equal(t, 1, pool.evidenceList.Len())
|
|
|
|
// if we send it again, it shouldnt add and return an error
|
|
err = pool.AddEvidence(goodEvidence)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, pool.evidenceList.Len())
|
|
}
|
|
|
|
func TestProposingAndCommittingEvidence(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
height = int64(1)
|
|
stateDB = initializeValidatorState(val, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), val.PrivKey.PubKey().Address())
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
// evidence not seen yet:
|
|
evidence := types.NewMockDuplicateVoteEvidenceWithValidator(height, evidenceTime, val, evidenceChainID)
|
|
assert.False(t, pool.IsCommitted(evidence))
|
|
|
|
// evidence seen but not yet committed:
|
|
assert.NoError(t, pool.AddEvidence(evidence))
|
|
assert.False(t, pool.IsCommitted(evidence))
|
|
|
|
// test evidence is proposed
|
|
proposedEvidence := pool.AllPendingEvidence()
|
|
assert.Equal(t, proposedEvidence[0], evidence)
|
|
|
|
// evidence seen and committed:
|
|
pool.MarkEvidenceAsCommitted(height, proposedEvidence)
|
|
assert.True(t, pool.IsCommitted(evidence))
|
|
assert.False(t, pool.IsPending(evidence))
|
|
assert.Equal(t, 0, pool.evidenceList.Len())
|
|
|
|
// evidence should
|
|
}
|
|
|
|
func TestAddEvidence(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
valAddr = val.PrivKey.PubKey().Address()
|
|
height = int64(30)
|
|
stateDB = initializeValidatorState(val, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
evHeight int64
|
|
evTime time.Time
|
|
expErr bool
|
|
evDescription string
|
|
}{
|
|
{height, time.Now(), false, "valid evidence"},
|
|
{height, evidenceTime, false, "valid evidence (despite old time)"},
|
|
{int64(1), time.Now(), false, "valid evidence (despite old height)"},
|
|
{int64(1), evidenceTime, true,
|
|
"evidence from height 1 (created at: 2019-01-01 00:00:00 +0000 UTC) is too old"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.evDescription, func(t *testing.T) {
|
|
ev := types.NewMockDuplicateVoteEvidence(tc.evHeight, tc.evTime, evidenceChainID)
|
|
err := pool.AddEvidence(ev)
|
|
if tc.expErr {
|
|
assert.Error(t, err)
|
|
t.Log(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEvidencePoolUpdate(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
valAddr = val.PrivKey.PubKey().Address()
|
|
height = int64(21)
|
|
stateDB = initializeValidatorState(val, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
state = sm.LoadState(stateDB)
|
|
blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
|
|
)
|
|
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
// create new block (no need to save it to blockStore)
|
|
evidence := types.NewMockDuplicateVoteEvidence(height, time.Now(), evidenceChainID)
|
|
lastCommit := makeCommit(height, valAddr)
|
|
block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{evidence})
|
|
// update state (partially)
|
|
state.LastBlockHeight = height + 1
|
|
|
|
pool.Update(block, state)
|
|
|
|
// a) Update marks evidence as committed
|
|
assert.True(t, pool.IsCommitted(evidence))
|
|
}
|
|
|
|
func TestAddingAndPruningPOLC(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
valAddr = val.PrivKey.PubKey().Address()
|
|
stateDB = initializeValidatorState(val, 1)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
state = sm.LoadState(stateDB)
|
|
blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
|
|
height = state.ConsensusParams.Evidence.MaxAgeNumBlocks * 2
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
firstBlockID = types.BlockID{
|
|
Hash: tmrand.Bytes(tmhash.Size),
|
|
PartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: tmrand.Bytes(tmhash.Size),
|
|
},
|
|
}
|
|
)
|
|
|
|
voteA := makeVote(1, 1, 0, val.PrivKey.PubKey().Address(), firstBlockID, evidenceTime)
|
|
vA := voteA.ToProto()
|
|
err := val.SignVote(evidenceChainID, vA)
|
|
require.NoError(t, err)
|
|
voteA.Signature = vA.Signature
|
|
|
|
pubKey, _ := types.NewMockPV().GetPubKey()
|
|
polc := &types.ProofOfLockChange{
|
|
Votes: []*types.Vote{voteA},
|
|
PubKey: pubKey,
|
|
}
|
|
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
err = pool.AddPOLC(polc)
|
|
assert.NoError(t, err)
|
|
|
|
// should be able to retrieve polc
|
|
newPolc, err := pool.RetrievePOLC(1, 1)
|
|
assert.NoError(t, err)
|
|
assert.True(t, polc.Equal(newPolc))
|
|
|
|
// should not be able to retrieve because it doesn't exist
|
|
emptyPolc, err := pool.RetrievePOLC(2, 1)
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, emptyPolc)
|
|
|
|
lastCommit := makeCommit(height-1, valAddr)
|
|
block := types.MakeBlock(height, []types.Tx{}, lastCommit, []types.Evidence{})
|
|
// update state (partially)
|
|
state.LastBlockHeight = height
|
|
pool.state.LastBlockHeight = height
|
|
|
|
// update should prune the polc
|
|
pool.Update(block, state)
|
|
|
|
emptyPolc, err = pool.RetrievePOLC(1, 1)
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, emptyPolc)
|
|
|
|
}
|
|
|
|
func TestRecoverPendingEvidence(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
valAddr = val.PrivKey.PubKey().Address()
|
|
height = int64(30)
|
|
stateDB = initializeValidatorState(val, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
state = sm.LoadState(stateDB)
|
|
blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
goodEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), val, evidenceChainID)
|
|
expiredEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(int64(1), evidenceTime, val, evidenceChainID)
|
|
)
|
|
|
|
// load good evidence
|
|
goodKey := keyPending(goodEvidence)
|
|
evi, err := types.EvidenceToProto(goodEvidence)
|
|
require.NoError(t, err)
|
|
goodEvidenceBytes, err := proto.Marshal(evi)
|
|
require.NoError(t, err)
|
|
_ = evidenceDB.Set(goodKey, goodEvidenceBytes)
|
|
|
|
// load expired evidence
|
|
expiredKey := keyPending(expiredEvidence)
|
|
eevi, err := types.EvidenceToProto(expiredEvidence)
|
|
require.NoError(t, err)
|
|
|
|
expiredEvidenceBytes, err := proto.Marshal(eevi)
|
|
require.NoError(t, err)
|
|
|
|
_ = evidenceDB.Set(expiredKey, expiredEvidenceBytes)
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, pool.evidenceList.Len())
|
|
assert.True(t, pool.IsPending(goodEvidence))
|
|
}
|
|
|
|
// Comprehensive set of test cases relating to the adding, upgrading and overall
|
|
// processing of PotentialAmnesiaEvidence and AmnesiaEvidence
|
|
func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
|
|
var (
|
|
val = types.NewMockPV()
|
|
val2 = types.NewMockPV()
|
|
pubKey = val.PrivKey.PubKey()
|
|
pubKey2 = val2.PrivKey.PubKey()
|
|
valSet = &types.ValidatorSet{
|
|
Validators: []*types.Validator{
|
|
val.ExtractIntoValidator(1),
|
|
val2.ExtractIntoValidator(3),
|
|
},
|
|
Proposer: val.ExtractIntoValidator(1),
|
|
}
|
|
height = int64(30)
|
|
stateDB = initializeStateFromValidatorSet(valSet, height)
|
|
evidenceDB = dbm.NewMemDB()
|
|
blockStoreDB = dbm.NewMemDB()
|
|
state = sm.LoadState(stateDB)
|
|
blockStore = initializeBlockStore(blockStoreDB, state, pubKey.Address())
|
|
//evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
firstBlockID = types.BlockID{
|
|
Hash: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
|
PartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
|
},
|
|
}
|
|
secondBlockID = types.BlockID{
|
|
Hash: []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
|
|
PartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
|
|
},
|
|
}
|
|
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
// TEST SETUP
|
|
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
|
require.NoError(t, err)
|
|
|
|
pool.SetLogger(log.TestingLogger())
|
|
|
|
voteA := makeVote(height, 0, 0, pubKey.Address(), firstBlockID, evidenceTime)
|
|
vA := voteA.ToProto()
|
|
err = val.SignVote(evidenceChainID, vA)
|
|
voteA.Signature = vA.Signature
|
|
require.NoError(t, err)
|
|
voteB := makeVote(height, 1, 0, pubKey.Address(), secondBlockID, evidenceTime.Add(3*time.Second))
|
|
vB := voteB.ToProto()
|
|
err = val.SignVote(evidenceChainID, vB)
|
|
voteB.Signature = vB.Signature
|
|
require.NoError(t, err)
|
|
voteC := makeVote(height, 2, 0, pubKey.Address(), firstBlockID, evidenceTime.Add(2*time.Second))
|
|
vC := voteC.ToProto()
|
|
err = val.SignVote(evidenceChainID, vC)
|
|
voteC.Signature = vC.Signature
|
|
require.NoError(t, err)
|
|
ev := &types.PotentialAmnesiaEvidence{
|
|
VoteA: voteA,
|
|
VoteB: voteB,
|
|
}
|
|
|
|
polc := &types.ProofOfLockChange{
|
|
Votes: []*types.Vote{voteB},
|
|
PubKey: pubKey2,
|
|
}
|
|
err = pool.AddPOLC(polc)
|
|
require.NoError(t, err)
|
|
|
|
polc, err = pool.RetrievePOLC(height, 1)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, polc)
|
|
|
|
secondValVote := makeVote(height, 1, 0, pubKey2.Address(), secondBlockID, evidenceTime.Add(1*time.Second))
|
|
vv2 := secondValVote.ToProto()
|
|
err = val2.SignVote(evidenceChainID, vv2)
|
|
require.NoError(t, err)
|
|
secondValVote.Signature = vv2.Signature
|
|
|
|
validPolc := &types.ProofOfLockChange{
|
|
Votes: []*types.Vote{secondValVote},
|
|
PubKey: pubKey,
|
|
}
|
|
|
|
// CASE A
|
|
pool.logger.Info("CASE A")
|
|
// we expect the evidence pool to find the polc but log an error as the polc is not valid -> vote was
|
|
// not from a validator in this set. However, an error isn't thrown because the evidence pool
|
|
// should still be able to save the regular potential amnesia evidence.
|
|
err = pool.AddEvidence(ev)
|
|
assert.NoError(t, err)
|
|
|
|
// evidence requires trial period until it is available -> we expect no evidence to be returned
|
|
assert.Equal(t, 0, len(pool.PendingEvidence(1)))
|
|
assert.True(t, pool.IsOnTrial(ev))
|
|
|
|
nextHeight := pool.nextEvidenceTrialEndedHeight
|
|
assert.Greater(t, nextHeight, int64(0))
|
|
|
|
// CASE B
|
|
pool.logger.Info("CASE B")
|
|
// evidence is not ready to be upgraded so we return the height we expect the evidence to be.
|
|
nextHeight = pool.upgradePotentialAmnesiaEvidence()
|
|
assert.Equal(t, height+pool.state.ConsensusParams.Evidence.ProofTrialPeriod, nextHeight)
|
|
|
|
// CASE C
|
|
pool.logger.Info("CASE C")
|
|
// now evidence is ready to be upgraded to amnesia evidence -> we expect -1 to be the next height as their is
|
|
// no more pending potential amnesia evidence left
|
|
lastCommit := makeCommit(height+1, pubKey.Address())
|
|
block := types.MakeBlock(height+2, []types.Tx{}, lastCommit, []types.Evidence{})
|
|
state.LastBlockHeight = height + 2
|
|
|
|
pool.Update(block, state)
|
|
assert.Equal(t, int64(-1), pool.nextEvidenceTrialEndedHeight)
|
|
|
|
assert.Equal(t, 1, len(pool.PendingEvidence(1)))
|
|
|
|
// CASE D
|
|
pool.logger.Info("CASE D")
|
|
// evidence of voting back in the past which is instantly punishable -> amnesia evidence is made directly
|
|
ev2 := &types.PotentialAmnesiaEvidence{
|
|
VoteA: voteC,
|
|
VoteB: voteB,
|
|
}
|
|
err = pool.AddEvidence(ev2)
|
|
assert.NoError(t, err)
|
|
expectedAe := &types.AmnesiaEvidence{
|
|
PotentialAmnesiaEvidence: ev2,
|
|
Polc: types.NewEmptyPOLC(),
|
|
}
|
|
|
|
assert.True(t, pool.IsPending(expectedAe))
|
|
assert.Equal(t, 2, len(pool.AllPendingEvidence()))
|
|
|
|
// CASE E
|
|
pool.logger.Info("CASE E")
|
|
// test for receiving amnesia evidence
|
|
ae := types.NewAmnesiaEvidence(ev, types.NewEmptyPOLC())
|
|
// we need to run the trial period ourselves so amnesia evidence should not be added, instead
|
|
// we should extract out the potential amnesia evidence and trying to add that before realising
|
|
// that we already have it -> no error
|
|
err = pool.AddEvidence(ae)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(pool.AllPendingEvidence()))
|
|
|
|
voteD := makeVote(height, 2, 0, pubKey.Address(), firstBlockID, evidenceTime.Add(4*time.Second))
|
|
vD := voteD.ToProto()
|
|
err = val.SignVote(evidenceChainID, vD)
|
|
require.NoError(t, err)
|
|
voteD.Signature = vD.Signature
|
|
|
|
// CASE F
|
|
pool.logger.Info("CASE F")
|
|
// a new amnesia evidence is seen. It has an empty polc so we should extract the potential amnesia evidence
|
|
// and start our own trial
|
|
newPe := &types.PotentialAmnesiaEvidence{
|
|
VoteA: voteB,
|
|
VoteB: voteD,
|
|
}
|
|
newAe := &types.AmnesiaEvidence{
|
|
PotentialAmnesiaEvidence: newPe,
|
|
Polc: types.NewEmptyPOLC(),
|
|
}
|
|
err = pool.AddEvidence(newAe)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(pool.AllPendingEvidence()))
|
|
assert.True(t, pool.IsOnTrial(newPe))
|
|
|
|
// CASE G
|
|
pool.logger.Info("CASE G")
|
|
// Finally, we receive an amnesia evidence containing a valid polc for an earlier potential amnesia evidence
|
|
// that we have already upgraded to. We should ad this new amnesia evidence in replace of the prior
|
|
// amnesia evidence with an empty polc that we have
|
|
aeWithPolc := &types.AmnesiaEvidence{
|
|
PotentialAmnesiaEvidence: ev,
|
|
Polc: validPolc,
|
|
}
|
|
err = pool.AddEvidence(aeWithPolc)
|
|
assert.NoError(t, err)
|
|
assert.True(t, pool.IsPending(aeWithPolc))
|
|
assert.Equal(t, 2, len(pool.AllPendingEvidence()))
|
|
t.Log(pool.AllPendingEvidence())
|
|
|
|
}
|
|
|
|
func initializeStateFromValidatorSet(valSet *types.ValidatorSet, height int64) dbm.DB {
|
|
stateDB := dbm.NewMemDB()
|
|
state := sm.State{
|
|
ChainID: evidenceChainID,
|
|
LastBlockHeight: height,
|
|
LastBlockTime: tmtime.Now(),
|
|
Validators: valSet,
|
|
NextValidators: valSet.CopyIncrementProposerPriority(1),
|
|
LastValidators: valSet,
|
|
LastHeightValidatorsChanged: 1,
|
|
ConsensusParams: tmproto.ConsensusParams{
|
|
Block: tmproto.BlockParams{
|
|
MaxBytes: 22020096,
|
|
MaxGas: -1,
|
|
},
|
|
Evidence: tmproto.EvidenceParams{
|
|
MaxAgeNumBlocks: 20,
|
|
MaxAgeDuration: 48 * time.Hour,
|
|
MaxNum: 50,
|
|
ProofTrialPeriod: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
// save all states up to height
|
|
for i := int64(0); i <= height; i++ {
|
|
state.LastBlockHeight = i
|
|
sm.SaveState(stateDB, state)
|
|
}
|
|
|
|
return stateDB
|
|
}
|
|
|
|
func initializeValidatorState(privVal types.PrivValidator, height int64) dbm.DB {
|
|
|
|
pubKey, _ := privVal.GetPubKey()
|
|
validator := &types.Validator{Address: pubKey.Address(), VotingPower: 0, PubKey: pubKey}
|
|
|
|
// create validator set and state
|
|
valSet := &types.ValidatorSet{
|
|
Validators: []*types.Validator{validator},
|
|
Proposer: validator,
|
|
}
|
|
|
|
return initializeStateFromValidatorSet(valSet, height)
|
|
}
|
|
|
|
// initializeBlockStore creates a block storage and populates it w/ a dummy
|
|
// block at +height+.
|
|
func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore {
|
|
blockStore := store.NewBlockStore(db)
|
|
|
|
for i := int64(1); i <= state.LastBlockHeight; i++ {
|
|
lastCommit := makeCommit(i-1, valAddr)
|
|
block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil,
|
|
state.Validators.GetProposer().Address)
|
|
|
|
const parts = 1
|
|
partSet := block.MakePartSet(parts)
|
|
|
|
seenCommit := makeCommit(i, valAddr)
|
|
blockStore.SaveBlock(block, partSet, seenCommit)
|
|
}
|
|
|
|
return blockStore
|
|
}
|
|
|
|
func makeCommit(height int64, valAddr []byte) *types.Commit {
|
|
commitSigs := []types.CommitSig{{
|
|
BlockIDFlag: types.BlockIDFlagCommit,
|
|
ValidatorAddress: valAddr,
|
|
Timestamp: time.Now(),
|
|
Signature: []byte("Signature"),
|
|
}}
|
|
return types.NewCommit(height, 0, types.BlockID{}, commitSigs)
|
|
}
|
|
|
|
func makeVote(height int64, round, index int32, addr bytes.HexBytes,
|
|
blockID types.BlockID, time time.Time) *types.Vote {
|
|
return &types.Vote{
|
|
Type: tmproto.SignedMsgType(2),
|
|
Height: height,
|
|
Round: round,
|
|
BlockID: blockID,
|
|
Timestamp: time,
|
|
ValidatorAddress: addr,
|
|
ValidatorIndex: index,
|
|
}
|
|
}
|