diff --git a/types/evidence_test.go b/types/evidence_test.go index 3187b324a..9d54797e4 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -2,6 +2,7 @@ package types import ( "context" + "encoding/hex" "math" mrand "math/rand" "testing" @@ -11,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/tmhash" tmrand "github.com/tendermint/tendermint/libs/rand" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -281,22 +283,6 @@ func TestEvidenceProto(t *testing.T) { v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime) v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime) - // -------- SignedHeaders -------- - const height int64 = 37 - - var ( - header1 = makeHeaderRandom() - header2 = makeHeaderRandom() - ) - - header1.Height = height - header1.LastBlockID = blockID - header1.ChainID = chainID - - header2.Height = height - header2.LastBlockID = blockID - header2.ChainID = chainID - tests := []struct { testName string evidence Evidence @@ -328,3 +314,80 @@ func TestEvidenceProto(t *testing.T) { }) } } + +func TestEvidenceVectors(t *testing.T) { + // Votes for duplicateEvidence + val := NewMockPV() + val.PrivKey = ed25519.GenPrivKeyFromSecret([]byte("it's a secret")) // deterministic key + blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash"))) + blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash"))) + const chainID = "mychain" + v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime) + v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime) + + // Data for LightClientAttackEvidence + height := int64(5) + commonHeight := height - 1 + nValidators := 10 + voteSet, valSet, privVals := deterministicVoteSet(height, 1, tmproto.PrecommitType, 1) + header := &Header{ + Version: version.Consensus{Block: 1, App: 1}, + ChainID: chainID, + Height: height, + Time: time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC), + LastBlockID: BlockID{}, + LastCommitHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + DataHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + ValidatorsHash: valSet.Hash(), + NextValidatorsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + ConsensusHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + AppHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + + LastResultsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + + EvidenceHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"), + ProposerAddress: []byte("2915b7b15f979e48ebc61774bb1d86ba3136b7eb"), + } + blockID3 := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash"))) + commit, err := makeCommit(blockID3, height, 1, voteSet, privVals, defaultVoteTime) + require.NoError(t, err) + lcae := &LightClientAttackEvidence{ + ConflictingBlock: &LightBlock{ + SignedHeader: &SignedHeader{ + Header: header, + Commit: commit, + }, + ValidatorSet: valSet, + }, + CommonHeight: commonHeight, + TotalVotingPower: valSet.TotalVotingPower(), + Timestamp: header.Time, + ByzantineValidators: valSet.Validators[:nValidators/2], + } + // assert.NoError(t, lcae.ValidateBasic()) + + testCases := []struct { + testName string + evList EvidenceList + expBytes string + }{ + {"duplicateVoteEvidence", + EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}}, + "a9ce28d13bb31001fc3e5b7927051baf98f86abdbd64377643a304164c826923", + }, + {"LightClientAttackEvidence", + EvidenceList{lcae}, + "2f8782163c3905b26e65823ababc977fe54e97b94e60c0360b1e4726b668bb8e", + }, + {"LightClientAttackEvidence & DuplicateVoteEvidence", + EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}, lcae}, + "eedb4b47d6dbc9d43f53da8aa50bb826e8d9fc7d897da777c8af6a04aa74163e", + }, + } + + for _, tc := range testCases { + tc := tc + hash := tc.evList.Hash() + require.Equal(t, tc.expBytes, hex.EncodeToString(hash), tc.testName) + } +} diff --git a/types/validator_set_test.go b/types/validator_set_test.go index 1f5d7d82e..a69121344 100644 --- a/types/validator_set_test.go +++ b/types/validator_set_test.go @@ -1592,3 +1592,27 @@ func BenchmarkValidatorSet_VerifyCommitLightTrusting_Ed25519(b *testing.B) { }) } } + +// Testing Utils + +// deterministicValidatorSet returns a deterministic validator set (size: +numValidators+), +// where each validator has a power of 50 +// +// EXPOSED FOR TESTING. +func deterministicValidatorSet() (*ValidatorSet, []PrivValidator) { + var ( + valz = make([]*Validator, 10) + privValidators = make([]PrivValidator, 10) + ) + + for i := 0; i < 10; i++ { + // val, privValidator := DeterministicValidator(ed25519.PrivKey([]byte(deterministicKeys[i]))) + val, privValidator := deterministicValidator(ed25519.GenPrivKeyFromSecret([]byte(fmt.Sprintf("key: %x", i)))) + valz[i] = val + privValidators[i] = privValidator + } + + sort.Sort(PrivValidatorsByAddress(privValidators)) + + return NewValidatorSet(valz), privValidators +} diff --git a/types/validator_test.go b/types/validator_test.go index 04d02d5aa..872dee820 100644 --- a/types/validator_test.go +++ b/types/validator_test.go @@ -2,10 +2,12 @@ package types import ( "context" + "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" ) func TestValidatorProtoBuf(t *testing.T) { @@ -98,3 +100,19 @@ func TestValidatorValidateBasic(t *testing.T) { } } } + +// Testing util functions + +// deterministicValidator returns a deterministic validator, useful for testing. +// UNSTABLE +func deterministicValidator(key crypto.PrivKey) (*Validator, PrivValidator) { + privVal := NewMockPV() + privVal.PrivKey = key + var votePower int64 = 50 + pubKey, err := privVal.GetPubKey(context.TODO()) + if err != nil { + panic(fmt.Errorf("could not retrieve pubkey %w", err)) + } + val := NewValidator(pubKey, votePower) + return val, privVal +} diff --git a/types/vote_set_test.go b/types/vote_set_test.go index cf1eb916f..ef009aacc 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -488,6 +488,16 @@ func randVoteSet( return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators } +func deterministicVoteSet( + height int64, + round int32, + signedMsgType tmproto.SignedMsgType, + votingPower int64, +) (*VoteSet, *ValidatorSet, []PrivValidator) { + valSet, privValidators := deterministicValidatorSet() + return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators +} + func randValidatorPrivValSet(numValidators int, votingPower int64) (*ValidatorSet, []PrivValidator) { var ( valz = make([]*Validator, numValidators)