From b11d9ae5b78785fe776643da76537d0220d082c1 Mon Sep 17 00:00:00 2001 From: shotonoff Date: Thu, 4 Nov 2021 12:56:09 +0100 Subject: [PATCH 1/6] docs(e2e): add description about how to keep validators public keys at full node --- test/e2e/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/e2e/README.md b/test/e2e/README.md index da323a5380..ba630443e5 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -82,6 +82,18 @@ func init() { } ``` +### Full-node keys + +Since Full nodes do not participate in the consensus process, then keeping validators' public keys also is not required. +By default, public keys are reset during network generation. However, if you need to keep its, then use this env +parameter `FULLNODE_PUBKEY_KEEP=true`. + +For instance: + +```bash +FULLNODE_PUBKEY_KEEP=true make runner/dashcore +``` + ### Speed up running e2e tests Running the e2e tests using `make runner {network}` takes time because the From e906ca1e6f2fb3b2ef50ad51cdde0370b7b366a6 Mon Sep 17 00:00:00 2001 From: shotonoff Date: Thu, 4 Nov 2021 13:19:05 +0100 Subject: [PATCH 2/6] docs(e2e): add information how to sue preset for network generation --- test/e2e/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/e2e/README.md b/test/e2e/README.md index ba630443e5..898f918aac 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -30,6 +30,12 @@ Multiple testnets can be run with the `run-multiple.sh` script: ./run-multiple.sh networks/generated/gen-group3-*.toml ``` +In order to generate network configurations with settings for dash, you have to override a default preset with `dash`. + +```sh +./build/generator -d networks/generated/ -p dash +``` + ## Test Stages The test runner has the following stages, which can also be executed explicitly by running `./build/runner -f `: From 7163a1ec8ec93d88b0945f324bafe171e85f9f14 Mon Sep 17 00:00:00 2001 From: shotonoff Date: Thu, 4 Nov 2021 13:20:25 +0100 Subject: [PATCH 3/6] docs(e2e): change a type of code block --- test/e2e/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index 898f918aac..33e6f04caf 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -96,7 +96,7 @@ parameter `FULLNODE_PUBKEY_KEEP=true`. For instance: -```bash +```sh FULLNODE_PUBKEY_KEEP=true make runner/dashcore ``` From 07e31182c5d30852c7ade2ce6cab72010a9b74d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 11:05:11 +0000 Subject: [PATCH 4/6] build(deps): bump technote-space/get-diff-action from 5.0.1 to 5.0.2 Bumps [technote-space/get-diff-action](https://github.com/technote-space/get-diff-action) from 5.0.1 to 5.0.2. - [Release notes](https://github.com/technote-space/get-diff-action/releases) - [Changelog](https://github.com/technote-space/get-diff-action/blob/main/.releasegarc) - [Commits](https://github.com/technote-space/get-diff-action/compare/v5.0.1...v5.0.2) --- updated-dependencies: - dependency-name: technote-space/get-diff-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/coverage.yml | 6 +++--- .github/workflows/e2e.yml | 4 ++-- .github/workflows/lint.yaml | 2 +- .github/workflows/tests.yml | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 66f9de0fd4..b8d577e46c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -86,7 +86,7 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -118,7 +118,7 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -156,7 +156,7 @@ jobs: run: | echo "::set-output name=hash::$(git --git-dir=third_party/bls-signatures/src/.git rev-parse HEAD)" shell: bash - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 43e115bba0..325fd3c87a 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -63,7 +63,7 @@ jobs: run: | echo "::set-output name=hash::$(git --git-dir=third_party/bls-signatures/src/.git rev-parse HEAD)" shell: bash - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -111,7 +111,7 @@ jobs: run: | echo "::set-output name=hash::$(git --git-dir=third_party/bls-signatures/src/.git rev-parse HEAD)" shell: bash - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index addb299b8f..4a6af17954 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -58,7 +58,7 @@ jobs: run: | echo "::set-output name=hash::$(git --git-dir=third_party/bls-signatures/src/.git rev-parse HEAD)" shell: bash - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4d99c10998..40de11639c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,7 +63,7 @@ jobs: with: go-version: "^1.15.5" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -95,7 +95,7 @@ jobs: with: go-version: "^1.15.5" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -135,7 +135,7 @@ jobs: with: go-version: "^1.15.5" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go @@ -166,7 +166,7 @@ jobs: with: go-version: "^1.15.5" - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v5.0.1 + - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | **/**.go From 438bb246a2c84aafb624f715b56a35371b0a8246 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 18 Nov 2021 16:30:42 +0100 Subject: [PATCH 5/6] fix: panic on precommits does not have any +2/3 votes --- types/validator_set.go | 1 + types/vote_set.go | 3 +- types/vote_set_test.go | 143 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/types/validator_set.go b/types/validator_set.go index ffcf162176..c4bde50ba6 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -524,6 +524,7 @@ func (vals *ValidatorSet) QuorumVotingPower() int64 { } // QuorumVotingThresholdPower returns the threshold power of the voting power of the quorum if all the members existed. +// Voting is considered successful when voting power is at or above this threshold. func (vals *ValidatorSet) QuorumVotingThresholdPower() int64 { return int64(vals.QuorumTypeThresholdCount()) * DefaultDashVotingPower } diff --git a/types/vote_set.go b/types/vote_set.go index 05c4cbf490..6d9086398f 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -507,13 +507,14 @@ func (voteSet *VoteSet) IsCommit() bool { return voteSet.maj23 != nil } +// HasTwoThirdsAny returns true if we are above voting threshold, regardless of the block id voted func (voteSet *VoteSet) HasTwoThirdsAny() bool { if voteSet == nil { return false } voteSet.mtx.Lock() defer voteSet.mtx.Unlock() - return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3 + return voteSet.sum >= voteSet.valSet.QuorumVotingThresholdPower() } func (voteSet *VoteSet) HasAll() bool { diff --git a/types/vote_set_test.go b/types/vote_set_test.go index edd2402c20..f22ecd8d80 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -2,12 +2,16 @@ package types import ( "bytes" + "math" + "sort" + "strconv" "testing" + "github.com/dashevo/dashd-go/btcjson" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/bls12381" tmrand "github.com/tendermint/tendermint/libs/rand" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -519,6 +523,112 @@ func TestVoteSet_MakeCommit(t *testing.T) { } } +func TestVoteSet_LLMQType_50_60(t *testing.T) { + testCases := []struct { + llmqType btcjson.LLMQType + numValidators int + threshold int + }{ + { + llmqType: btcjson.LLMQType(0), // "tendermint" algorithm + numValidators: 40, + threshold: int(math.Floor(2.0/3.0*40)) + 1, + }, + { + llmqType: btcjson.LLMQType_50_60, + numValidators: 35, + threshold: 30, + }, + { + llmqType: btcjson.LLMQType(0), + numValidators: 50, + threshold: 34, + }, + { + llmqType: btcjson.LLMQType_50_60, + numValidators: 50, + threshold: 30, + }, + } + + for ti, tt := range testCases { + name := strconv.Itoa(ti) + t.Run(name, func(t *testing.T) { + height, round := int64(1), int32(0) + numValidators := tt.numValidators + llmqType := tt.llmqType + threshold := tt.threshold + + voteSet, valSet, privValidators := randVoteSetWithLLMQType( + height, + round, + tmproto.PrevoteType, + numValidators, + RandStateID().WithHeight(height-1), + llmqType, + threshold, + ) + assert.EqualValues(t, threshold, valSet.QuorumTypeThresholdCount()) + assert.GreaterOrEqual(t, len(privValidators), threshold+3) + + blockHash := crypto.CRandBytes(32) + blockPartSetHeader := PartSetHeader{uint32(123), crypto.CRandBytes(32)} + votedBlock := BlockID{blockHash, blockPartSetHeader} + + // below threshold + for i := 0; i < threshold-1; i++ { + blockMaj, anyMaj := castVote(t, votedBlock, height, round, privValidators, int32(i), voteSet) + assert.False(t, blockMaj, "no block majority expected here: i=%d, threshold=%d", i, threshold) + assert.False(t, anyMaj, "no 'any' majority expected here: i=%d, threshold=%d", i, threshold) + } + + // we add null vote + blockMaj, anyMaj := castVote(t, BlockID{}, height, round, privValidators, int32(threshold), voteSet) + assert.False(t, blockMaj, "no block majority expected after nil vote") + assert.True(t, anyMaj, "'any' majority expected after nil vote at threshold") + + // at threshold + blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(threshold+1), voteSet) + assert.True(t, blockMaj, "block majority expected") + assert.True(t, anyMaj, "'any' majority expected") + + // above threshold + blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(threshold+2), voteSet) + assert.True(t, blockMaj, "block majority expected") + assert.True(t, anyMaj, "'any' majority expected") + }) + } +} + +func castVote( + t *testing.T, + blockID BlockID, + height int64, + round int32, + privValidators []PrivValidator, + validatorID int32, + voteSet *VoteSet, +) (twoThirdsMajority, hasTwoThirdsAny bool) { + voteProto := &Vote{ + ValidatorProTxHash: nil, // NOTE: must fill in + ValidatorIndex: -1, // NOTE: must fill in + Height: height, + Round: round, + Type: tmproto.PrevoteType, + BlockID: blockID, + } + proTxHash, err := privValidators[validatorID].GetProTxHash() + require.NoError(t, err) + vote := withValidator(voteProto, proTxHash, validatorID) + signed, err := signAddVote(privValidators[validatorID], vote, voteSet) + require.True(t, signed) + require.NoError(t, err) + + majorityBlock, twoThirdsMajority := voteSet.TwoThirdsMajority() + assert.EqualValues(t, twoThirdsMajority, !majorityBlock.IsZero()) + return twoThirdsMajority, voteSet.HasTwoThirdsAny() +} + // NOTE: privValidators are in order func randVoteSet( height int64, @@ -531,6 +641,37 @@ func randVoteSet( return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet, stateID), valSet, privValidators } +func randVoteSetWithLLMQType( + height int64, + round int32, + signedMsgType tmproto.SignedMsgType, + numValidators int, + stateID StateID, + llmqType btcjson.LLMQType, + threshold int, +) (*VoteSet, *ValidatorSet, []PrivValidator) { + var ( + valz = make([]*Validator, numValidators) + privValidators = make([]PrivValidator, numValidators) + ) + privateKeys, proTxHashes, thresholdPublicKey := bls12381.CreatePrivLLMQData(numValidators, threshold) + quorumHash := crypto.RandQuorumHash() + + for i := 0; i < numValidators; i++ { + privValidators[i] = NewMockPVWithParams(privateKeys[i], proTxHashes[i], quorumHash, + thresholdPublicKey, false, false) + valz[i] = NewValidatorDefaultVotingPower(privateKeys[i].PubKey(), proTxHashes[i]) + } + + sort.Sort(PrivValidatorsByProTxHash(privValidators)) + + valSet := NewValidatorSet(valz, thresholdPublicKey, llmqType, quorumHash, true) + voteSet := NewVoteSet("test_chain_id", height, round, tmproto.PrevoteType, + valSet, stateID) + + return voteSet, valSet, privValidators +} + // Convenience: Return new vote with different validator address/index func withValidator(vote *Vote, proTxHash []byte, idx int32) *Vote { vote = vote.Copy() From fc463d6b900bb7fd17d9d774c541711703312742 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 19 Nov 2021 11:17:45 +0100 Subject: [PATCH 6/6] refactor(types): apply peer review feedback --- types/vote_set_test.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/types/vote_set_test.go b/types/vote_set_test.go index f22ecd8d80..982245319b 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -524,6 +524,10 @@ func TestVoteSet_MakeCommit(t *testing.T) { } func TestVoteSet_LLMQType_50_60(t *testing.T) { + const ( + height = int64(1) + round = int32(0) + ) testCases := []struct { llmqType btcjson.LLMQType numValidators int @@ -554,46 +558,42 @@ func TestVoteSet_LLMQType_50_60(t *testing.T) { for ti, tt := range testCases { name := strconv.Itoa(ti) t.Run(name, func(t *testing.T) { - height, round := int64(1), int32(0) - numValidators := tt.numValidators - llmqType := tt.llmqType - threshold := tt.threshold - voteSet, valSet, privValidators := randVoteSetWithLLMQType( height, round, tmproto.PrevoteType, - numValidators, + tt.numValidators, RandStateID().WithHeight(height-1), - llmqType, - threshold, + tt.llmqType, + tt.threshold, ) - assert.EqualValues(t, threshold, valSet.QuorumTypeThresholdCount()) - assert.GreaterOrEqual(t, len(privValidators), threshold+3) + assert.EqualValues(t, tt.threshold, valSet.QuorumTypeThresholdCount()) + assert.GreaterOrEqual(t, len(privValidators), tt.threshold+3, + "need at least %d validators", tt.threshold+3) blockHash := crypto.CRandBytes(32) blockPartSetHeader := PartSetHeader{uint32(123), crypto.CRandBytes(32)} votedBlock := BlockID{blockHash, blockPartSetHeader} // below threshold - for i := 0; i < threshold-1; i++ { + for i := 0; i < tt.threshold-1; i++ { blockMaj, anyMaj := castVote(t, votedBlock, height, round, privValidators, int32(i), voteSet) - assert.False(t, blockMaj, "no block majority expected here: i=%d, threshold=%d", i, threshold) - assert.False(t, anyMaj, "no 'any' majority expected here: i=%d, threshold=%d", i, threshold) + assert.False(t, blockMaj, "no block majority expected here: i=%d, threshold=%d", i, tt.threshold) + assert.False(t, anyMaj, "no 'any' majority expected here: i=%d, threshold=%d", i, tt.threshold) } // we add null vote - blockMaj, anyMaj := castVote(t, BlockID{}, height, round, privValidators, int32(threshold), voteSet) + blockMaj, anyMaj := castVote(t, BlockID{}, height, round, privValidators, int32(tt.threshold), voteSet) assert.False(t, blockMaj, "no block majority expected after nil vote") assert.True(t, anyMaj, "'any' majority expected after nil vote at threshold") // at threshold - blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(threshold+1), voteSet) + blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(tt.threshold+1), voteSet) assert.True(t, blockMaj, "block majority expected") assert.True(t, anyMaj, "'any' majority expected") // above threshold - blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(threshold+2), voteSet) + blockMaj, anyMaj = castVote(t, votedBlock, height, round, privValidators, int32(tt.threshold+2), voteSet) assert.True(t, blockMaj, "block majority expected") assert.True(t, anyMaj, "'any' majority expected") })