From 8eb67af419e2906ce75e950c1d0cd8887fdbc7a9 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 13 Apr 2023 13:03:00 +0200 Subject: [PATCH 1/2] test(types): sign_bytes tests synchronized with rs-tenderdash-abci --- proto/tendermint/types/types_test.go | 99 +++++++++++++++++++++------- types/vote_test.go | 15 +++++ 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/proto/tendermint/types/types_test.go b/proto/tendermint/types/types_test.go index 9414c9d8bf..56308a0f0b 100644 --- a/proto/tendermint/types/types_test.go +++ b/proto/tendermint/types/types_test.go @@ -1,6 +1,8 @@ package types import ( + "bytes" + "encoding/hex" "strconv" "testing" time "time" @@ -9,39 +11,90 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/internal/libs/protoio" "github.com/tendermint/tendermint/libs/rand" ) +// TestVoteSignBytes checks if sign bytes are generated correctly. +// +// This test is synchronized with tests in github.com/dashpay/rs-tenderdash-abci func TestVoteSignBytes(t *testing.T) { const ( - height = 1 - round = 2 + height = 1 + round = 2 + chainID = "some-chain" ) - h := rand.Bytes(crypto.HashSize) - stateID := StateID{ - AppVersion: 2, - Height: height, - AppHash: h, - CoreChainLockedHeight: 1, - Time: *gogotypes.TimestampNow(), + ts := &gogotypes.Timestamp{} + h := bytes.Repeat([]byte{1, 2, 3, 4}, 8) + + type testCase struct { + stateID StateID + vote Vote + expectHex string } - sidHash := stateID.Hash() - v := Vote{ - Type: PrecommitType, - Height: height, - Round: round, - BlockID: BlockID{ - Hash: h, - PartSetHeader: PartSetHeader{Total: 1, Hash: h}, - StateID: sidHash, + + testCases := []testCase{ + 0: { + stateID: StateID{ + AppVersion: 2, + Height: height, + AppHash: h, + CoreChainLockedHeight: 1, + Time: *ts, + }, + vote: Vote{ + Type: PrevoteType, + Height: height, + Round: round, + BlockID: BlockID{ + Hash: h, + PartSetHeader: PartSetHeader{Total: 1, Hash: h}, + StateID: []byte{}, // filled later + }, + }, + expectHex: "0100000001000000000000000200000000000000fb7c89bf010a91d50f890455582b7fed0c346e53ab" + + "33df7da0bcd85c10fa92ead7509905b5407ee72dadd93b4ae70a24ad8a7755fc677acd2b215710a05cfc47736" + + "f6d652d636861696e", + }, + 1: { + stateID: StateID{ + AppVersion: 2, + Height: height, + AppHash: h, + CoreChainLockedHeight: 1, + Time: *ts, + }, + vote: Vote{ + Type: PrecommitType, + Height: height, + Round: round, + BlockID: BlockID{ + Hash: h, + PartSetHeader: PartSetHeader{Total: 1, Hash: h}, + StateID: []byte{}, // filled later + }, + }, + expectHex: "0200000001000000000000000200000000000000fb7c89bf010a91d50f8904" + + "55582b7fed0c346e53ab33df7da0bcd85c10fa92ead7509905b5407ee72dadd93b4ae70a2" + + "4ad8a7755fc677acd2b215710a05cfc47736f6d652d636861696e", }, } - const chainID = "some-chain" - sb, err := v.SignBytes(chainID) - require.NoError(t, err) - assert.Len(t, sb, 4+8+8+32+32+len(chainID)) // type(4) + height(8) + round(8) + blockID(32) + stateID(32) + + for i, tc := range testCases { + t.Run(strconv.Itoa(i), func(t *testing.T) { + vote := tc.vote + vote.BlockID.StateID = tc.stateID.Hash() + expected, err := hex.DecodeString(tc.expectHex) + require.NoError(t, err) + + sb, err := vote.SignBytes(chainID) + require.NoError(t, err) + assert.Len(t, sb, 4+8+8+32+32+len(chainID)) // type(4) + height(8) + round(8) + blockID(32) + stateID(32) + assert.EqualValues(t, expected, sb) + + t.Logf("state ID hash: %x sign bytes: %x", vote.BlockID.StateID, sb) + }) + } } func TestStateID_Equals(t *testing.T) { diff --git a/types/vote_test.go b/types/vote_test.go index f1f366e313..78d9c2a116 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -615,6 +615,21 @@ func TestInvalidPrecommitExtensions(t *testing.T) { } } +// TestVoteExtensionsSignBytes checks if vote extension sign bytes are generated correctly. +// +// This test is synchronized with tests from github.com/dashpay/rs-tenderdash-abci +func TestVoteExtensionsSignBytes(t *testing.T) { + expect := hexBytesFromString(t, "2a0a080102030405060708110100000000000000190200000000000000220a736f6d652d636861696e2801") + ve := tmproto.VoteExtension{ + Extension: []byte{1, 2, 3, 4, 5, 6, 7, 8}, + Signature: []byte{}, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + } + actual := VoteExtensionSignBytes("some-chain", 1, 2, &ve) + t.Logf("sign bytes: %x", actual) + assert.EqualValues(t, expect, actual) +} + func TestVoteProtobuf(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() From 37ac5da526a2b8eca745050fcc642b07fb5b9367 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:46:42 +0200 Subject: [PATCH 2/2] test(types): make some tests deterministic --- internal/consensus/vote_signer_test.go | 10 ++++++++ types/quorum_sign_data_test.go | 6 +++++ types/vote_test.go | 34 ++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index a594a07836..43ca8582cd 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + bls "github.com/dashpay/bls-signatures/go-bindings" + cstypes "github.com/tendermint/tendermint/internal/consensus/types" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/mocks" @@ -133,6 +135,14 @@ func TestVoteSigner_signAddVote(t *testing.T) { Return(nil) vote := signer.signAddVote(ctx, &stateData, tc.msgType, tc.blockID) assert.NotNil(t, vote) + key, err := privVal.GetPubKey(ctx, valSet.QuorumHash) + assert.NoError(t, err) + + key1, err := bls.G1ElementFromBytes(key.Bytes()) + assert.NoError(t, err) + + t.Logf("key: %x", key1.Serialize()) + t.Logf("%+v", vote.VoteExtensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER]) }) } } diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 056fb36502..e6a56ba502 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -14,6 +14,12 @@ import ( "github.com/tendermint/tendermint/proto/tendermint/types" ) +func TestBlockRequestID(t *testing.T) { + expected := tmbytes.MustHexDecode("28277743e77872951df01bda93a344feca2435e113b8824ce636eada665aadd5") + got := BlockRequestID(12, 34) + assert.EqualValues(t, expected, got) +} + func TestMakeBlockSignID(t *testing.T) { const chainID = "dash-platform" testCases := []struct { diff --git a/types/vote_test.go b/types/vote_test.go index 78d9c2a116..e8bcb0534e 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -1,12 +1,15 @@ package types import ( + "bytes" "context" "fmt" "testing" + bls "github.com/dashpay/bls-signatures/go-bindings" "github.com/dashpay/dashd-go/btcjson" "github.com/gogo/protobuf/proto" + gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -44,19 +47,31 @@ func examplePrecommit(t testing.TB) *Vote { } func exampleVote(tb testing.TB, t byte) *Vote { - tb.Helper() + const ( + height = 12345 + round = 2 + ) + appHash := bytes.Repeat([]byte{1, 2, 3, 4}, 8) + tb.Helper() + stateID := tmproto.StateID{ + Height: height, + AppHash: appHash, + AppVersion: StateIDVersion, + CoreChainLockedHeight: 3, + Time: gogotypes.Timestamp{}, + } return &Vote{ Type: tmproto.SignedMsgType(t), - Height: 12345, - Round: 2, + Height: height, + Round: round, BlockID: BlockID{ Hash: crypto.Checksum([]byte("blockID_hash")), PartSetHeader: PartSetHeader{ Total: 1000000, Hash: crypto.Checksum([]byte("blockID_part_set_header_hash")), }, - StateID: RandStateID().Hash(), + StateID: stateID.Hash(), }, ValidatorProTxHash: crypto.ProTxHashFromSeedBytes([]byte("validator_pro_tx_hash")), ValidatorIndex: 56789, @@ -253,7 +268,7 @@ func TestVoteVerifySignature(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - quorumHash := crypto.RandQuorumHash() + quorumHash := make([]byte, 32) privVal := NewMockPVForQuorum(quorumHash) pubkey, err := privVal.GetPubKey(context.Background(), quorumHash) require.NoError(t, err) @@ -271,6 +286,15 @@ func TestVoteVerifySignature(t *testing.T) { valid := pubkey.VerifySignatureDigest(signID, v.BlockSignature) require.True(t, valid) + g1, err := bls.G1ElementFromBytes(pubkey.Bytes()) + require.NoError(t, err) + signBytes, err := v.SignBytes("test_chain_id") + require.NoError(t, err) + t.Logf("-> pubkey: %s\n-> sign bytes: %x\n-> signID: %x\n-> signature: %x", + g1.HexString(), + signBytes, + signID, + v.BlockSignature) // serialize, deserialize and verify again.... precommit := new(tmproto.Vote) bs, err := proto.Marshal(v)