github.com/noirx94/tendermintmp@v0.0.1/types/proposal_test.go (about) 1 package types 2 3 import ( 4 "math" 5 "testing" 6 "time" 7 8 "github.com/gogo/protobuf/proto" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/tendermint/tendermint/crypto/tmhash" 13 "github.com/tendermint/tendermint/libs/protoio" 14 tmrand "github.com/tendermint/tendermint/libs/rand" 15 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 16 ) 17 18 var ( 19 testProposal *Proposal 20 pbp *tmproto.Proposal 21 ) 22 23 func init() { 24 var stamp, err = time.Parse(TimeFormat, "2018-02-11T07:09:22.765Z") 25 if err != nil { 26 panic(err) 27 } 28 testProposal = &Proposal{ 29 Height: 12345, 30 Round: 23456, 31 BlockID: BlockID{Hash: []byte("--June_15_2020_amino_was_removed"), 32 PartSetHeader: PartSetHeader{Total: 111, Hash: []byte("--June_15_2020_amino_was_removed")}}, 33 POLRound: -1, 34 Timestamp: stamp, 35 } 36 pbp = testProposal.ToProto() 37 } 38 39 func TestProposalSignable(t *testing.T) { 40 chainID := "test_chain_id" 41 signBytes := ProposalSignBytes(chainID, pbp) 42 pb := CanonicalizeProposal(chainID, pbp) 43 44 expected, err := protoio.MarshalDelimited(&pb) 45 require.NoError(t, err) 46 require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Proposal") 47 } 48 49 func TestProposalString(t *testing.T) { 50 str := testProposal.String() 51 expected := `Proposal{12345/23456 (2D2D4A756E655F31355F323032305F616D696E6F5F7761735F72656D6F766564:111:2D2D4A756E65, -1) 000000000000 @ 2018-02-11T07:09:22.765Z}` //nolint:lll // ignore line length for tests 52 if str != expected { 53 t.Errorf("got unexpected string for Proposal. Expected:\n%v\nGot:\n%v", expected, str) 54 } 55 } 56 57 func TestProposalVerifySignature(t *testing.T) { 58 privVal := NewMockPV() 59 pubKey, err := privVal.GetPubKey() 60 require.NoError(t, err) 61 62 prop := NewProposal( 63 4, 2, 2, 64 BlockID{tmrand.Bytes(tmhash.Size), PartSetHeader{777, tmrand.Bytes(tmhash.Size)}}) 65 p := prop.ToProto() 66 signBytes := ProposalSignBytes("test_chain_id", p) 67 68 // sign it 69 err = privVal.SignProposal("test_chain_id", p) 70 require.NoError(t, err) 71 prop.Signature = p.Signature 72 73 // verify the same proposal 74 valid := pubKey.VerifySignature(signBytes, prop.Signature) 75 require.True(t, valid) 76 77 // serialize, deserialize and verify again.... 78 newProp := new(tmproto.Proposal) 79 pb := prop.ToProto() 80 81 bs, err := proto.Marshal(pb) 82 require.NoError(t, err) 83 84 err = proto.Unmarshal(bs, newProp) 85 require.NoError(t, err) 86 87 np, err := ProposalFromProto(newProp) 88 require.NoError(t, err) 89 90 // verify the transmitted proposal 91 newSignBytes := ProposalSignBytes("test_chain_id", pb) 92 require.Equal(t, string(signBytes), string(newSignBytes)) 93 valid = pubKey.VerifySignature(newSignBytes, np.Signature) 94 require.True(t, valid) 95 } 96 97 func BenchmarkProposalWriteSignBytes(b *testing.B) { 98 for i := 0; i < b.N; i++ { 99 ProposalSignBytes("test_chain_id", pbp) 100 } 101 } 102 103 func BenchmarkProposalSign(b *testing.B) { 104 privVal := NewMockPV() 105 for i := 0; i < b.N; i++ { 106 err := privVal.SignProposal("test_chain_id", pbp) 107 if err != nil { 108 b.Error(err) 109 } 110 } 111 } 112 113 func BenchmarkProposalVerifySignature(b *testing.B) { 114 privVal := NewMockPV() 115 err := privVal.SignProposal("test_chain_id", pbp) 116 require.NoError(b, err) 117 pubKey, err := privVal.GetPubKey() 118 require.NoError(b, err) 119 120 for i := 0; i < b.N; i++ { 121 pubKey.VerifySignature(ProposalSignBytes("test_chain_id", pbp), testProposal.Signature) 122 } 123 } 124 125 func TestProposalValidateBasic(t *testing.T) { 126 127 privVal := NewMockPV() 128 testCases := []struct { 129 testName string 130 malleateProposal func(*Proposal) 131 expectErr bool 132 }{ 133 {"Good Proposal", func(p *Proposal) {}, false}, 134 {"Invalid Type", func(p *Proposal) { p.Type = tmproto.PrecommitType }, true}, 135 {"Invalid Height", func(p *Proposal) { p.Height = -1 }, true}, 136 {"Invalid Round", func(p *Proposal) { p.Round = -1 }, true}, 137 {"Invalid POLRound", func(p *Proposal) { p.POLRound = -2 }, true}, 138 {"Invalid BlockId", func(p *Proposal) { 139 p.BlockID = BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}} 140 }, true}, 141 {"Invalid Signature", func(p *Proposal) { 142 p.Signature = make([]byte, 0) 143 }, true}, 144 {"Too big Signature", func(p *Proposal) { 145 p.Signature = make([]byte, MaxSignatureSize+1) 146 }, true}, 147 } 148 blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash"))) 149 150 for _, tc := range testCases { 151 tc := tc 152 t.Run(tc.testName, func(t *testing.T) { 153 prop := NewProposal( 154 4, 2, 2, 155 blockID) 156 p := prop.ToProto() 157 err := privVal.SignProposal("test_chain_id", p) 158 prop.Signature = p.Signature 159 require.NoError(t, err) 160 tc.malleateProposal(prop) 161 assert.Equal(t, tc.expectErr, prop.ValidateBasic() != nil, "Validate Basic had an unexpected result") 162 }) 163 } 164 } 165 166 func TestProposalProtoBuf(t *testing.T) { 167 proposal := NewProposal(1, 2, 3, makeBlockID([]byte("hash"), 2, []byte("part_set_hash"))) 168 proposal.Signature = []byte("sig") 169 proposal2 := NewProposal(1, 2, 3, BlockID{}) 170 171 testCases := []struct { 172 msg string 173 p1 *Proposal 174 expPass bool 175 }{ 176 {"success", proposal, true}, 177 {"success", proposal2, false}, // blcokID cannot be empty 178 {"empty proposal failure validatebasic", &Proposal{}, false}, 179 {"nil proposal", nil, false}, 180 } 181 for _, tc := range testCases { 182 protoProposal := tc.p1.ToProto() 183 184 p, err := ProposalFromProto(protoProposal) 185 if tc.expPass { 186 require.NoError(t, err) 187 require.Equal(t, tc.p1, p, tc.msg) 188 } else { 189 require.Error(t, err) 190 } 191 } 192 }