github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/crypto/tmhash"
    13  	"github.com/vipernet-xyz/tm/libs/protoio"
    14  	tmrand "github.com/vipernet-xyz/tm/libs/rand"
    15  	tmproto "github.com/vipernet-xyz/tm/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  }