From 9dc562b467c9638032a0c11e45a648c3cf857b02 Mon Sep 17 00:00:00 2001 From: Tim <96273851+timtim-git@users.noreply.github.com> Date: Thu, 23 Dec 2021 17:25:43 +0800 Subject: [PATCH] - Fix failure to generate all possible combinations (backport #3132) * - Fix failure to generate all possible combinations Bug happens when the endorsement policy is set to k-out-of-n where (n - k) > 1. For example, when there are 6 organizations and the endorsement policy is set to majority (i.e. 4-out-of-6). The combinations calculated by chooseKoutOfN() in original code are as below. [0 1 2 5], [0 1 2 5], [0 1 2 5], [0 1 3 5], [0 1 3 5], [0 1 4 5], [0 2 3 5], [0 2 3 5], [0 2 4 5], [0 3 4 5], [1 2 3 5], [1 2 3 5], [1 2 4 5], [1 3 4 5], [2 3 4 5] Obviously, the function fails to find out all the possible combinations. Some of the combinations are overrided by child's call. This bug would trigger below error sometimes when the alive peers are not within the above combinations. [discovery] chaincodeQuery -> ERRO 13a Failed constructing descriptor for chaincode chaincodes: ,: no peer combination can satisfy the endorsement policy To fix it, the last line of choose() should be changed to pass a copy of "currentSubGroup" to the recursive call instead, i.e. choose(n, targetAmount, i+1, append(make([]int, 0), currentSubGroup...), subGroups) After applying the fix, the resulting combinations generated should be corrected as below. [0 1 2 3], [0 1 2 4], [0 1 2 5], [0 1 3 4], [0 1 3 5], [0 1 4 5], [0 2 3 4], [0 2 3 5], [0 2 4 5], [0 3 4 5], [1 2 3 4], [1 2 3 5], [1 2 4 5], [1 3 4 5], [2 3 4 5] Signed-off-by: Tim <96273851+timtim-git@users.noreply.github.com> * - Fix failure to generate all possible combinations Bug happens when the endorsement policy is set to k-out-of-n where (n - k) > 1. For example, when there are 6 organizations and the endorsement policy is set to majority (i.e. 4-out-of-6). The combinations calculated by chooseKoutOfN() in original code are as below. [0 1 2 5], [0 1 2 5], [0 1 2 5], [0 1 3 5], [0 1 3 5], [0 1 4 5], [0 2 3 5], [0 2 3 5], [0 2 4 5], [0 3 4 5], [1 2 3 5], [1 2 3 5], [1 2 4 5], [1 3 4 5], [2 3 4 5] Obviously, the function fails to find out all the possible combinations. Some of the combinations are overrided by child's call. This bug would trigger below error sometimes when the alive peers are not within the above combinations. [discovery] chaincodeQuery -> ERRO 13a Failed constructing descriptor for chaincode chaincodes: ,: no peer combination can satisfy the endorsement policy To fix it, the last line of choose() should be changed to pass a copy of "currentSubGroup" to the recursive call instead, i.e. choose(n, targetAmount, i+1, append(make([]int, 0), currentSubGroup...), subGroups) After applying the fix, the resulting combinations generated should be corrected as below. [0 1 2 3], [0 1 2 4], [0 1 2 5], [0 1 3 4], [0 1 3 5], [0 1 4 5], [0 2 3 4], [0 2 3 5], [0 2 4 5], [0 3 4 5], [1 2 3 4], [1 2 3 5], [1 2 4 5], [1 3 4 5], [2 3 4 5] Signed-off-by: Tim <96273851+timtim-git@users.noreply.github.com> * - Update choose_test.go Signed-off-by: Tim <96273851+timtim-git@users.noreply.github.com> * - Fix build error Signed-off-by: Tim <96273851+timtim-git@users.noreply.github.com> Signed-off-by: David Enyeart --- common/graph/choose.go | 9 ++++++++- common/graph/choose_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/common/graph/choose.go b/common/graph/choose.go index 08a6ce0dc49..d7df824868f 100644 --- a/common/graph/choose.go +++ b/common/graph/choose.go @@ -59,7 +59,14 @@ func choose(n int, targetAmount int, i int, currentSubGroup []int, subGroups *or return } // We either pick the current element - choose(n, targetAmount, i+1, append(currentSubGroup, i), subGroups) + choose(n, targetAmount, i+1, concatInts(currentSubGroup, i), subGroups) // Or don't pick it choose(n, targetAmount, i+1, currentSubGroup, subGroups) } + +func concatInts(a []int, elements ...int) []int { + var res []int + res = append(res, a...) + res = append(res, elements...) + return res +} diff --git a/common/graph/choose_test.go b/common/graph/choose_test.go index 442b4f0f178..b67f7187493 100644 --- a/common/graph/choose_test.go +++ b/common/graph/choose_test.go @@ -7,9 +7,11 @@ SPDX-License-Identifier: Apache-2.0 package graph import ( + "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCombinationsExceed(t *testing.T) { @@ -24,3 +26,32 @@ func TestCombinationsExceed(t *testing.T) { // N < K returns false assert.False(t, CombinationsExceed(20, 30, 0)) } + +func TestChooseKoutOfN(t *testing.T) { + expectedSets := indiceSets{ + &indiceSet{[]int{0, 1, 2, 3}}, + &indiceSet{[]int{0, 1, 2, 4}}, + &indiceSet{[]int{0, 1, 2, 5}}, + &indiceSet{[]int{0, 1, 3, 4}}, + &indiceSet{[]int{0, 1, 3, 5}}, + &indiceSet{[]int{0, 1, 4, 5}}, + &indiceSet{[]int{0, 2, 3, 4}}, + &indiceSet{[]int{0, 2, 3, 5}}, + &indiceSet{[]int{0, 2, 4, 5}}, + &indiceSet{[]int{0, 3, 4, 5}}, + &indiceSet{[]int{1, 2, 3, 4}}, + &indiceSet{[]int{1, 2, 3, 5}}, + &indiceSet{[]int{1, 2, 4, 5}}, + &indiceSet{[]int{1, 3, 4, 5}}, + &indiceSet{[]int{2, 3, 4, 5}}, + } + require.Equal(t, indiceSetsToStrings(expectedSets), indiceSetsToStrings(chooseKoutOfN(6, 4))) +} + +func indiceSetsToStrings(sets indiceSets) []string { + var res []string + for _, set := range sets { + res = append(res, fmt.Sprintf("%v", set.indices)) + } + return res +}