mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-07 13:55:17 +00:00
## Description - Add `context.Context` to Privval interface This pr does not introduce context into our custom privval connection protocol because this will be removed in the next release. When this pr is released.
739 lines
20 KiB
Go
739 lines
20 KiB
Go
package consensus
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
|
"github.com/tendermint/tendermint/crypto/merkle"
|
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
|
"github.com/tendermint/tendermint/libs/bits"
|
|
"github.com/tendermint/tendermint/libs/bytes"
|
|
tmrand "github.com/tendermint/tendermint/libs/rand"
|
|
"github.com/tendermint/tendermint/p2p"
|
|
tmcons "github.com/tendermint/tendermint/proto/tendermint/consensus"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
func TestMsgToProto(t *testing.T) {
|
|
psh := types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: tmrand.Bytes(32),
|
|
}
|
|
pbPsh := psh.ToProto()
|
|
bi := types.BlockID{
|
|
Hash: tmrand.Bytes(32),
|
|
PartSetHeader: psh,
|
|
}
|
|
pbBi := bi.ToProto()
|
|
bits := bits.NewBitArray(1)
|
|
pbBits := bits.ToProto()
|
|
|
|
parts := types.Part{
|
|
Index: 1,
|
|
Bytes: []byte("test"),
|
|
Proof: merkle.Proof{
|
|
Total: 1,
|
|
Index: 1,
|
|
LeafHash: tmrand.Bytes(32),
|
|
Aunts: [][]byte{},
|
|
},
|
|
}
|
|
pbParts, err := parts.ToProto()
|
|
require.NoError(t, err)
|
|
|
|
proposal := types.Proposal{
|
|
Type: tmproto.ProposalType,
|
|
Height: 1,
|
|
Round: 1,
|
|
POLRound: 1,
|
|
BlockID: bi,
|
|
Timestamp: time.Now(),
|
|
Signature: tmrand.Bytes(20),
|
|
}
|
|
pbProposal := proposal.ToProto()
|
|
|
|
pv := types.NewMockPV()
|
|
pk, err := pv.GetPubKey(context.Background())
|
|
require.NoError(t, err)
|
|
val := types.NewValidator(pk, 100)
|
|
|
|
vote, err := types.MakeVote(
|
|
1, types.BlockID{}, &types.ValidatorSet{Proposer: val, Validators: []*types.Validator{val}},
|
|
pv, "chainID", time.Now())
|
|
require.NoError(t, err)
|
|
pbVote := vote.ToProto()
|
|
|
|
testsCases := []struct {
|
|
testName string
|
|
msg Message
|
|
want *tmcons.Message
|
|
wantErr bool
|
|
}{
|
|
{"successful NewRoundStepMessage", &NewRoundStepMessage{
|
|
Height: 2,
|
|
Round: 1,
|
|
Step: 1,
|
|
SecondsSinceStartTime: 1,
|
|
LastCommitRound: 2,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_NewRoundStep{
|
|
NewRoundStep: &tmcons.NewRoundStep{
|
|
Height: 2,
|
|
Round: 1,
|
|
Step: 1,
|
|
SecondsSinceStartTime: 1,
|
|
LastCommitRound: 2,
|
|
},
|
|
},
|
|
}, false},
|
|
|
|
{"successful NewValidBlockMessage", &NewValidBlockMessage{
|
|
Height: 1,
|
|
Round: 1,
|
|
BlockPartSetHeader: psh,
|
|
BlockParts: bits,
|
|
IsCommit: false,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_NewValidBlock{
|
|
NewValidBlock: &tmcons.NewValidBlock{
|
|
Height: 1,
|
|
Round: 1,
|
|
BlockPartSetHeader: pbPsh,
|
|
BlockParts: pbBits,
|
|
IsCommit: false,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful BlockPartMessage", &BlockPartMessage{
|
|
Height: 100,
|
|
Round: 1,
|
|
Part: &parts,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_BlockPart{
|
|
BlockPart: &tmcons.BlockPart{
|
|
Height: 100,
|
|
Round: 1,
|
|
Part: *pbParts,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful ProposalPOLMessage", &ProposalPOLMessage{
|
|
Height: 1,
|
|
ProposalPOLRound: 1,
|
|
ProposalPOL: bits,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_ProposalPol{
|
|
ProposalPol: &tmcons.ProposalPOL{
|
|
Height: 1,
|
|
ProposalPolRound: 1,
|
|
ProposalPol: *pbBits,
|
|
},
|
|
}}, false},
|
|
{"successful ProposalMessage", &ProposalMessage{
|
|
Proposal: &proposal,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_Proposal{
|
|
Proposal: &tmcons.Proposal{
|
|
Proposal: *pbProposal,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful VoteMessage", &VoteMessage{
|
|
Vote: vote,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_Vote{
|
|
Vote: &tmcons.Vote{
|
|
Vote: pbVote,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful VoteSetMaj23", &VoteSetMaj23Message{
|
|
Height: 1,
|
|
Round: 1,
|
|
Type: 1,
|
|
BlockID: bi,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_VoteSetMaj23{
|
|
VoteSetMaj23: &tmcons.VoteSetMaj23{
|
|
Height: 1,
|
|
Round: 1,
|
|
Type: 1,
|
|
BlockID: pbBi,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful VoteSetBits", &VoteSetBitsMessage{
|
|
Height: 1,
|
|
Round: 1,
|
|
Type: 1,
|
|
BlockID: bi,
|
|
Votes: bits,
|
|
}, &tmcons.Message{
|
|
Sum: &tmcons.Message_VoteSetBits{
|
|
VoteSetBits: &tmcons.VoteSetBits{
|
|
Height: 1,
|
|
Round: 1,
|
|
Type: 1,
|
|
BlockID: pbBi,
|
|
Votes: *pbBits,
|
|
},
|
|
},
|
|
}, false},
|
|
{"failure", nil, &tmcons.Message{}, true},
|
|
}
|
|
for _, tt := range testsCases {
|
|
tt := tt
|
|
t.Run(tt.testName, func(t *testing.T) {
|
|
pb, err := MsgToProto(tt.msg)
|
|
if tt.wantErr == true {
|
|
assert.Equal(t, err != nil, tt.wantErr)
|
|
return
|
|
}
|
|
assert.EqualValues(t, tt.want, pb, tt.testName)
|
|
|
|
msg, err := MsgFromProto(pb)
|
|
|
|
if !tt.wantErr {
|
|
require.NoError(t, err)
|
|
bcm := assert.Equal(t, tt.msg, msg, tt.testName)
|
|
assert.True(t, bcm, tt.testName)
|
|
} else {
|
|
require.Error(t, err, tt.testName)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWALMsgProto(t *testing.T) {
|
|
|
|
parts := types.Part{
|
|
Index: 1,
|
|
Bytes: []byte("test"),
|
|
Proof: merkle.Proof{
|
|
Total: 1,
|
|
Index: 1,
|
|
LeafHash: tmrand.Bytes(32),
|
|
Aunts: [][]byte{},
|
|
},
|
|
}
|
|
pbParts, err := parts.ToProto()
|
|
require.NoError(t, err)
|
|
|
|
testsCases := []struct {
|
|
testName string
|
|
msg WALMessage
|
|
want *tmcons.WALMessage
|
|
wantErr bool
|
|
}{
|
|
{"successful EventDataRoundState", types.EventDataRoundState{
|
|
Height: 2,
|
|
Round: 1,
|
|
Step: "ronies",
|
|
}, &tmcons.WALMessage{
|
|
Sum: &tmcons.WALMessage_EventDataRoundState{
|
|
EventDataRoundState: &tmproto.EventDataRoundState{
|
|
Height: 2,
|
|
Round: 1,
|
|
Step: "ronies",
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful msgInfo", msgInfo{
|
|
Msg: &BlockPartMessage{
|
|
Height: 100,
|
|
Round: 1,
|
|
Part: &parts,
|
|
},
|
|
PeerID: p2p.NodeID("string"),
|
|
}, &tmcons.WALMessage{
|
|
Sum: &tmcons.WALMessage_MsgInfo{
|
|
MsgInfo: &tmcons.MsgInfo{
|
|
Msg: tmcons.Message{
|
|
Sum: &tmcons.Message_BlockPart{
|
|
BlockPart: &tmcons.BlockPart{
|
|
Height: 100,
|
|
Round: 1,
|
|
Part: *pbParts,
|
|
},
|
|
},
|
|
},
|
|
PeerID: "string",
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful timeoutInfo", timeoutInfo{
|
|
Duration: time.Duration(100),
|
|
Height: 1,
|
|
Round: 1,
|
|
Step: 1,
|
|
}, &tmcons.WALMessage{
|
|
Sum: &tmcons.WALMessage_TimeoutInfo{
|
|
TimeoutInfo: &tmcons.TimeoutInfo{
|
|
Duration: time.Duration(100),
|
|
Height: 1,
|
|
Round: 1,
|
|
Step: 1,
|
|
},
|
|
},
|
|
}, false},
|
|
{"successful EndHeightMessage", EndHeightMessage{
|
|
Height: 1,
|
|
}, &tmcons.WALMessage{
|
|
Sum: &tmcons.WALMessage_EndHeight{
|
|
EndHeight: &tmcons.EndHeight{
|
|
Height: 1,
|
|
},
|
|
},
|
|
}, false},
|
|
{"failure", nil, &tmcons.WALMessage{}, true},
|
|
}
|
|
for _, tt := range testsCases {
|
|
tt := tt
|
|
t.Run(tt.testName, func(t *testing.T) {
|
|
pb, err := WALToProto(tt.msg)
|
|
if tt.wantErr == true {
|
|
assert.Equal(t, err != nil, tt.wantErr)
|
|
return
|
|
}
|
|
assert.EqualValues(t, tt.want, pb, tt.testName)
|
|
|
|
msg, err := WALFromProto(pb)
|
|
|
|
if !tt.wantErr {
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.msg, msg, tt.testName) // need the concrete type as WAL Message is a empty interface
|
|
} else {
|
|
require.Error(t, err, tt.testName)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// nolint:lll //ignore line length for tests
|
|
func TestConsMsgsVectors(t *testing.T) {
|
|
date := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC)
|
|
psh := types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: []byte("add_more_exclamation_marks_code-"),
|
|
}
|
|
pbPsh := psh.ToProto()
|
|
|
|
bi := types.BlockID{
|
|
Hash: []byte("add_more_exclamation_marks_code-"),
|
|
PartSetHeader: psh,
|
|
}
|
|
pbBi := bi.ToProto()
|
|
bits := bits.NewBitArray(1)
|
|
pbBits := bits.ToProto()
|
|
|
|
parts := types.Part{
|
|
Index: 1,
|
|
Bytes: []byte("test"),
|
|
Proof: merkle.Proof{
|
|
Total: 1,
|
|
Index: 1,
|
|
LeafHash: []byte("add_more_exclamation_marks_code-"),
|
|
Aunts: [][]byte{},
|
|
},
|
|
}
|
|
pbParts, err := parts.ToProto()
|
|
require.NoError(t, err)
|
|
|
|
proposal := types.Proposal{
|
|
Type: tmproto.ProposalType,
|
|
Height: 1,
|
|
Round: 1,
|
|
POLRound: 1,
|
|
BlockID: bi,
|
|
Timestamp: date,
|
|
Signature: []byte("add_more_exclamation"),
|
|
}
|
|
pbProposal := proposal.ToProto()
|
|
|
|
v := &types.Vote{
|
|
ValidatorAddress: []byte("add_more_exclamation"),
|
|
ValidatorIndex: 1,
|
|
Height: 1,
|
|
Round: 0,
|
|
Timestamp: date,
|
|
Type: tmproto.PrecommitType,
|
|
BlockID: bi,
|
|
}
|
|
vpb := v.ToProto()
|
|
|
|
testCases := []struct {
|
|
testName string
|
|
cMsg proto.Message
|
|
expBytes string
|
|
}{
|
|
{"NewRoundStep", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
|
|
Height: 1,
|
|
Round: 1,
|
|
Step: 1,
|
|
SecondsSinceStartTime: 1,
|
|
LastCommitRound: 1,
|
|
}}}, "0a0a08011001180120012801"},
|
|
{"NewRoundStep Max", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
|
|
Height: math.MaxInt64,
|
|
Round: math.MaxInt32,
|
|
Step: math.MaxUint32,
|
|
SecondsSinceStartTime: math.MaxInt64,
|
|
LastCommitRound: math.MaxInt32,
|
|
}}}, "0a2608ffffffffffffffff7f10ffffffff0718ffffffff0f20ffffffffffffffff7f28ffffffff07"},
|
|
{"NewValidBlock", &tmcons.Message{Sum: &tmcons.Message_NewValidBlock{
|
|
NewValidBlock: &tmcons.NewValidBlock{
|
|
Height: 1, Round: 1, BlockPartSetHeader: pbPsh, BlockParts: pbBits, IsCommit: false}}},
|
|
"1231080110011a24080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d22050801120100"},
|
|
{"Proposal", &tmcons.Message{Sum: &tmcons.Message_Proposal{Proposal: &tmcons.Proposal{Proposal: *pbProposal}}},
|
|
"1a720a7008201001180120012a480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d320608c0b89fdc053a146164645f6d6f72655f6578636c616d6174696f6e"},
|
|
{"ProposalPol", &tmcons.Message{Sum: &tmcons.Message_ProposalPol{
|
|
ProposalPol: &tmcons.ProposalPOL{Height: 1, ProposalPolRound: 1}}},
|
|
"2206080110011a00"},
|
|
{"BlockPart", &tmcons.Message{Sum: &tmcons.Message_BlockPart{
|
|
BlockPart: &tmcons.BlockPart{Height: 1, Round: 1, Part: *pbParts}}},
|
|
"2a36080110011a3008011204746573741a26080110011a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
|
|
{"Vote", &tmcons.Message{Sum: &tmcons.Message_Vote{
|
|
Vote: &tmcons.Vote{Vote: vpb}}},
|
|
"32700a6e0802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e3801"},
|
|
{"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
|
|
HasVote: &tmcons.HasVote{Height: 1, Round: 1, Type: tmproto.PrevoteType, Index: 1}}},
|
|
"3a080801100118012001"},
|
|
{"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
|
|
HasVote: &tmcons.HasVote{Height: math.MaxInt64, Round: math.MaxInt32,
|
|
Type: tmproto.PrevoteType, Index: math.MaxInt32}}},
|
|
"3a1808ffffffffffffffff7f10ffffffff07180120ffffffff07"},
|
|
{"VoteSetMaj23", &tmcons.Message{Sum: &tmcons.Message_VoteSetMaj23{
|
|
VoteSetMaj23: &tmcons.VoteSetMaj23{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi}}},
|
|
"425008011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
|
|
{"VoteSetBits", &tmcons.Message{Sum: &tmcons.Message_VoteSetBits{
|
|
VoteSetBits: &tmcons.VoteSetBits{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi, Votes: *pbBits}}},
|
|
"4a5708011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a050801120100"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
bz, err := proto.Marshal(tc.cMsg)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tc.expBytes, hex.EncodeToString(bz))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
|
|
const (
|
|
validSignedMsgType tmproto.SignedMsgType = 0x01
|
|
invalidSignedMsgType tmproto.SignedMsgType = 0x03
|
|
)
|
|
|
|
validBlockID := types.BlockID{}
|
|
invalidBlockID := types.BlockID{
|
|
Hash: bytes.HexBytes{},
|
|
PartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: []byte{0},
|
|
},
|
|
}
|
|
|
|
testCases := []struct { // nolint: maligned
|
|
expectErr bool
|
|
messageRound int32
|
|
messageHeight int64
|
|
testName string
|
|
messageType tmproto.SignedMsgType
|
|
messageBlockID types.BlockID
|
|
}{
|
|
{false, 0, 0, "Valid Message", validSignedMsgType, validBlockID},
|
|
{true, -1, 0, "Invalid Message", validSignedMsgType, validBlockID},
|
|
{true, 0, -1, "Invalid Message", validSignedMsgType, validBlockID},
|
|
{true, 0, 0, "Invalid Message", invalidSignedMsgType, validBlockID},
|
|
{true, 0, 0, "Invalid Message", validSignedMsgType, invalidBlockID},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
message := VoteSetMaj23Message{
|
|
Height: tc.messageHeight,
|
|
Round: tc.messageRound,
|
|
Type: tc.messageType,
|
|
BlockID: tc.messageBlockID,
|
|
}
|
|
|
|
assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
|
|
testCases := []struct {
|
|
malleateFn func(*VoteSetBitsMessage)
|
|
expErr string
|
|
}{
|
|
{func(msg *VoteSetBitsMessage) {}, ""},
|
|
{func(msg *VoteSetBitsMessage) { msg.Height = -1 }, "negative Height"},
|
|
{func(msg *VoteSetBitsMessage) { msg.Type = 0x03 }, "invalid Type"},
|
|
{func(msg *VoteSetBitsMessage) {
|
|
msg.BlockID = types.BlockID{
|
|
Hash: bytes.HexBytes{},
|
|
PartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
Hash: []byte{0},
|
|
},
|
|
}
|
|
}, "wrong BlockID: wrong PartSetHeader: wrong Hash:"},
|
|
{func(msg *VoteSetBitsMessage) { msg.Votes = bits.NewBitArray(types.MaxVotesCount + 1) },
|
|
"votes bit array is too big: 10001, max: 10000"},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
|
|
msg := &VoteSetBitsMessage{
|
|
Height: 1,
|
|
Round: 0,
|
|
Type: 0x01,
|
|
Votes: bits.NewBitArray(1),
|
|
BlockID: types.BlockID{},
|
|
}
|
|
|
|
tc.malleateFn(msg)
|
|
err := msg.ValidateBasic()
|
|
if tc.expErr != "" && assert.Error(t, err) {
|
|
assert.Contains(t, err.Error(), tc.expErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRoundStepMessageValidateBasic(t *testing.T) {
|
|
testCases := []struct { // nolint: maligned
|
|
expectErr bool
|
|
messageRound int32
|
|
messageLastCommitRound int32
|
|
messageHeight int64
|
|
testName string
|
|
messageStep cstypes.RoundStepType
|
|
}{
|
|
{false, 0, 0, 0, "Valid Message", cstypes.RoundStepNewHeight},
|
|
{true, -1, 0, 0, "Negative round", cstypes.RoundStepNewHeight},
|
|
{true, 0, 0, -1, "Negative height", cstypes.RoundStepNewHeight},
|
|
{true, 0, 0, 0, "Invalid Step", cstypes.RoundStepCommit + 1},
|
|
// The following cases will be handled by ValidateHeight
|
|
{false, 0, 0, 1, "H == 1 but LCR != -1 ", cstypes.RoundStepNewHeight},
|
|
{false, 0, -1, 2, "H > 1 but LCR < 0", cstypes.RoundStepNewHeight},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
message := NewRoundStepMessage{
|
|
Height: tc.messageHeight,
|
|
Round: tc.messageRound,
|
|
Step: tc.messageStep,
|
|
LastCommitRound: tc.messageLastCommitRound,
|
|
}
|
|
|
|
err := message.ValidateBasic()
|
|
if tc.expectErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRoundStepMessageValidateHeight(t *testing.T) {
|
|
initialHeight := int64(10)
|
|
testCases := []struct { // nolint: maligned
|
|
expectErr bool
|
|
messageLastCommitRound int32
|
|
messageHeight int64
|
|
testName string
|
|
}{
|
|
{false, 0, 11, "Valid Message"},
|
|
{true, 0, -1, "Negative height"},
|
|
{true, 0, 0, "Zero height"},
|
|
{true, 0, 10, "Initial height but LCR != -1 "},
|
|
{true, -1, 11, "Normal height but LCR < 0"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
message := NewRoundStepMessage{
|
|
Height: tc.messageHeight,
|
|
Round: 0,
|
|
Step: cstypes.RoundStepNewHeight,
|
|
LastCommitRound: tc.messageLastCommitRound,
|
|
}
|
|
|
|
err := message.ValidateHeight(initialHeight)
|
|
if tc.expectErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewValidBlockMessageValidateBasic(t *testing.T) {
|
|
testCases := []struct {
|
|
malleateFn func(*NewValidBlockMessage)
|
|
expErr string
|
|
}{
|
|
{func(msg *NewValidBlockMessage) {}, ""},
|
|
{func(msg *NewValidBlockMessage) { msg.Height = -1 }, "negative Height"},
|
|
{func(msg *NewValidBlockMessage) { msg.Round = -1 }, "negative Round"},
|
|
{
|
|
func(msg *NewValidBlockMessage) { msg.BlockPartSetHeader.Total = 2 },
|
|
"blockParts bit array size 1 not equal to BlockPartSetHeader.Total 2",
|
|
},
|
|
{
|
|
func(msg *NewValidBlockMessage) {
|
|
msg.BlockPartSetHeader.Total = 0
|
|
msg.BlockParts = bits.NewBitArray(0)
|
|
},
|
|
"empty blockParts",
|
|
},
|
|
{
|
|
func(msg *NewValidBlockMessage) { msg.BlockParts = bits.NewBitArray(int(types.MaxBlockPartsCount) + 1) },
|
|
"blockParts bit array size 1602 not equal to BlockPartSetHeader.Total 1",
|
|
},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
|
|
msg := &NewValidBlockMessage{
|
|
Height: 1,
|
|
Round: 0,
|
|
BlockPartSetHeader: types.PartSetHeader{
|
|
Total: 1,
|
|
},
|
|
BlockParts: bits.NewBitArray(1),
|
|
}
|
|
|
|
tc.malleateFn(msg)
|
|
err := msg.ValidateBasic()
|
|
if tc.expErr != "" && assert.Error(t, err) {
|
|
assert.Contains(t, err.Error(), tc.expErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProposalPOLMessageValidateBasic(t *testing.T) {
|
|
testCases := []struct {
|
|
malleateFn func(*ProposalPOLMessage)
|
|
expErr string
|
|
}{
|
|
{func(msg *ProposalPOLMessage) {}, ""},
|
|
{func(msg *ProposalPOLMessage) { msg.Height = -1 }, "negative Height"},
|
|
{func(msg *ProposalPOLMessage) { msg.ProposalPOLRound = -1 }, "negative ProposalPOLRound"},
|
|
{func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(0) }, "empty ProposalPOL bit array"},
|
|
{func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(types.MaxVotesCount + 1) },
|
|
"proposalPOL bit array is too big: 10001, max: 10000"},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
|
|
msg := &ProposalPOLMessage{
|
|
Height: 1,
|
|
ProposalPOLRound: 1,
|
|
ProposalPOL: bits.NewBitArray(1),
|
|
}
|
|
|
|
tc.malleateFn(msg)
|
|
err := msg.ValidateBasic()
|
|
if tc.expErr != "" && assert.Error(t, err) {
|
|
assert.Contains(t, err.Error(), tc.expErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBlockPartMessageValidateBasic(t *testing.T) {
|
|
testPart := new(types.Part)
|
|
testPart.Proof.LeafHash = tmhash.Sum([]byte("leaf"))
|
|
testCases := []struct {
|
|
testName string
|
|
messageHeight int64
|
|
messageRound int32
|
|
messagePart *types.Part
|
|
expectErr bool
|
|
}{
|
|
{"Valid Message", 0, 0, testPart, false},
|
|
{"Invalid Message", -1, 0, testPart, true},
|
|
{"Invalid Message", 0, -1, testPart, true},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
message := BlockPartMessage{
|
|
Height: tc.messageHeight,
|
|
Round: tc.messageRound,
|
|
Part: tc.messagePart,
|
|
}
|
|
|
|
assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
|
})
|
|
}
|
|
|
|
message := BlockPartMessage{Height: 0, Round: 0, Part: new(types.Part)}
|
|
message.Part.Index = 1
|
|
|
|
assert.Equal(t, true, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
|
}
|
|
|
|
func TestHasVoteMessageValidateBasic(t *testing.T) {
|
|
const (
|
|
validSignedMsgType tmproto.SignedMsgType = 0x01
|
|
invalidSignedMsgType tmproto.SignedMsgType = 0x03
|
|
)
|
|
|
|
testCases := []struct { // nolint: maligned
|
|
expectErr bool
|
|
messageRound int32
|
|
messageIndex int32
|
|
messageHeight int64
|
|
testName string
|
|
messageType tmproto.SignedMsgType
|
|
}{
|
|
{false, 0, 0, 0, "Valid Message", validSignedMsgType},
|
|
{true, -1, 0, 0, "Invalid Message", validSignedMsgType},
|
|
{true, 0, -1, 0, "Invalid Message", validSignedMsgType},
|
|
{true, 0, 0, 0, "Invalid Message", invalidSignedMsgType},
|
|
{true, 0, 0, -1, "Invalid Message", validSignedMsgType},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
message := HasVoteMessage{
|
|
Height: tc.messageHeight,
|
|
Round: tc.messageRound,
|
|
Type: tc.messageType,
|
|
Index: tc.messageIndex,
|
|
}
|
|
|
|
assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
|
})
|
|
}
|
|
}
|