github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/types/proposal_test.go (about)

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