Skip to content

Commit

Permalink
Merge pull request #96 from orbs-network/feature/robust-sync
Browse files Browse the repository at this point in the history
check for honest in block proof
  • Loading branch information
gadcl authored Nov 4, 2020
2 parents caaf77d + 04267c8 commit bb44582
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 11 deletions.
4 changes: 2 additions & 2 deletions mainloop.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ func GetMemberIdsFromBlockProof(blockProofBytes []byte) ([]primitives.MemberId,
return committeeMembers, nil
}

func (m *MainLoop) ValidateBlockConsensus(ctx context.Context, block interfaces.Block, blockProofBytes []byte, prevBlock interfaces.Block, maybePrevBlockProofBytes []byte) error {
func (m *MainLoop) ValidateBlockConsensus(ctx context.Context, block interfaces.Block, blockProofBytes []byte, prevBlock interfaces.Block, maybePrevBlockProofBytes []byte, softVerify bool) error {
if m.worker == nil {
panic("ValidateBlockConsensus() worker is nil")
}
return m.worker.ValidateBlockConsensus(ctx, block, blockProofBytes, prevBlock, maybePrevBlockProofBytes)
return m.worker.ValidateBlockConsensus(ctx, block, blockProofBytes, prevBlock, maybePrevBlockProofBytes, softVerify)
}

// Called from outside to indicate Node Sync
Expand Down
23 changes: 23 additions & 0 deletions services/blockproof/test/blockproof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@ func TestAValidBlockProof(t *testing.T) {
})
}

func TestAValidBlockProofSoft(t *testing.T) {
test.WithContext(func(ctx context.Context) {
block1 := mocks.ABlock(interfaces.GenesisBlock)
block2 := mocks.ABlock(block1)
block3 := mocks.ABlock(block2)

net := network.ABasicTestNetwork(ctx)
net.StartConsensus(ctx)

node0 := net.Nodes[0]
node1 := net.Nodes[1]
node2 := net.Nodes[2]
node3 := net.Nodes[3]

blockProof := genBlockProofMessages(net.InstanceId, block3, 6, 0, node1).Raw()
prevBlockProof := genBlockProofMessages(net.InstanceId, block2, 3, 0, node1, node2, node3).Raw()
require.Error(t, node0.ValidateBlockConsensusSoft(ctx, block3, blockProof, block2, prevBlockProof))
blockProof = genBlockProofMessages(net.InstanceId, block3, 6, 0, node1, node2).Raw()
require.Nil(t, node0.ValidateBlockConsensusSoft(ctx, block3, blockProof, block2, prevBlockProof))
require.Error(t, node0.ValidateBlockConsensus(ctx, nil, blockProof, nil, prevBlockProof))
})
}

func TestAValidBlockProofWithNilPrevBlockProof(t *testing.T) {
test.WithContext(func(ctx context.Context) {
block1 := mocks.ABlock(interfaces.GenesisBlock)
Expand Down
37 changes: 33 additions & 4 deletions services/quorum/quorum.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,41 @@ func CalcQuorumWeight(committeeWeights []primitives.MemberWeight) uint {
return 1
}

return sum - uint(math.Floor(float64(sum-1)/3))
return sum - calcF(sum)
}

func CalcByzMaxWeight(committeeWeights []primitives.MemberWeight) uint {
sum := uint(0)
for _, weight := range committeeWeights {
sum += uint(weight)
}

if sum == 0 {
return sum
}

return calcF(sum)
}

func calcF(totalWeight uint) uint {
return uint(math.Floor(float64(totalWeight-1) / 3))
}

func IsQuorum(committeeSubset []primitives.MemberId, allCommitteeMembers []interfaces.CommitteeMember) (bool, uint, uint) {
weight := getCommitteeSubsetWeight(committeeSubset, allCommitteeMembers)

q := CalcQuorumWeight(GetWeights(allCommitteeMembers))
return weight >= q, weight, q
}

func HasHonest(committeeSubset []primitives.MemberId, allCommitteeMembers []interfaces.CommitteeMember) (bool, uint, uint) {
weight := getCommitteeSubsetWeight(committeeSubset, allCommitteeMembers)

b := CalcByzMaxWeight(GetWeights(allCommitteeMembers))
return weight > b, weight, b
}

func getCommitteeSubsetWeight(committeeSubset []primitives.MemberId, allCommitteeMembers []interfaces.CommitteeMember) uint {
subsetIdsSet := make(map[string]bool)
for _, id := range committeeSubset {
subsetIdsSet[id.String()] = true
Expand All @@ -45,7 +76,5 @@ func IsQuorum(committeeSubset []primitives.MemberId, allCommitteeMembers []inter
sum += uint(member.Weight)
}
}

q := CalcQuorumWeight(GetWeights(allCommitteeMembers))
return sum >= q, sum, q
return sum
}
61 changes: 61 additions & 0 deletions services/quorum/test/quorum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ func TestCommitteeQuorum(t *testing.T) {
require.Equal(t, uint(67), quorum.CalcQuorumWeight([]primitives.MemberWeight{10, 20, 70}))
}

func TestCommitteeByzMaxWeight(t *testing.T) {
require.Equal(t, uint(1), quorum.CalcByzMaxWeight([]primitives.MemberWeight{4}))
require.Equal(t, uint(1), quorum.CalcByzMaxWeight([]primitives.MemberWeight{5}))
require.Equal(t, uint(1), quorum.CalcByzMaxWeight([]primitives.MemberWeight{6}))
require.Equal(t, uint(2), quorum.CalcByzMaxWeight([]primitives.MemberWeight{7}))
require.Equal(t, uint(2), quorum.CalcByzMaxWeight([]primitives.MemberWeight{8}))
require.Equal(t, uint(2), quorum.CalcByzMaxWeight([]primitives.MemberWeight{9}))
require.Equal(t, uint(3), quorum.CalcByzMaxWeight([]primitives.MemberWeight{10}))
require.Equal(t, uint(3), quorum.CalcByzMaxWeight([]primitives.MemberWeight{11}))
require.Equal(t, uint(3), quorum.CalcByzMaxWeight([]primitives.MemberWeight{12}))
require.Equal(t, uint(6), quorum.CalcByzMaxWeight([]primitives.MemberWeight{21}))
require.Equal(t, uint(7), quorum.CalcByzMaxWeight([]primitives.MemberWeight{22}))
require.Equal(t, uint(33), quorum.CalcByzMaxWeight([]primitives.MemberWeight{100}))

require.Equal(t, uint(33), quorum.CalcByzMaxWeight([]primitives.MemberWeight{10, 90}))
require.Equal(t, uint(33), quorum.CalcByzMaxWeight([]primitives.MemberWeight{10, 20, 70}))
}

func genCommittee(weights []primitives.MemberWeight) []interfaces.CommitteeMember {
committee := make([]interfaces.CommitteeMember, len(weights))
for i, weight := range weights {
Expand Down Expand Up @@ -79,3 +97,46 @@ func TestIsQuorum(t *testing.T) {
require.Equal(t, uint(67), q)
require.Equal(t, uint(60), totalWeights)
}

func TestHasHonest(t *testing.T) {
committee := genCommittee([]primitives.MemberWeight{1, 6, 10, 23, 60})

ids := func(inds []int) []primitives.MemberId {
_ids := make([]primitives.MemberId, len(inds))
for i, ind := range inds {
_ids[i] = committee[ind].Id
}
return _ids
}

hasHonest, totalWeights, b := quorum.HasHonest(ids([]int{0, 1, 2}), committee)
require.Equal(t, false, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(17), totalWeights)

hasHonest, totalWeights, b = quorum.HasHonest(ids([]int{2, 3}), committee)
require.Equal(t, false, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(33), totalWeights)

hasHonest, totalWeights, b = quorum.HasHonest(ids([]int{3, 3}), committee)
require.Equal(t, false, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(23), totalWeights)

hasHonest, totalWeights, b = quorum.HasHonest(ids([]int{0, 2, 3}), committee)
require.Equal(t, true, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(34), totalWeights)

hasHonest, totalWeights, b = quorum.HasHonest(ids([]int{2, 3, 4}), committee)
require.Equal(t, true, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(93), totalWeights)

hasHonest, totalWeights, b = quorum.HasHonest(ids([]int{4, 4}), committee)
require.Equal(t, true, hasHonest)
require.Equal(t, uint(33), b)
require.Equal(t, uint(60), totalWeights)

}
9 changes: 8 additions & 1 deletion test/network/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,14 @@ func (node *Node) ValidateBlockConsensus(ctx context.Context, block interfaces.B
if node.leanHelix == nil {
panic("ValidateBlockConsensus(): leanhelix is nil")
}
return node.leanHelix.ValidateBlockConsensus(ctx, block, blockProof, prevBlock, prevBlockProof)
return node.leanHelix.ValidateBlockConsensus(ctx, block, blockProof, prevBlock, prevBlockProof, false)
}

func (node *Node) ValidateBlockConsensusSoft(ctx context.Context, block interfaces.Block, blockProof []byte, prevBlock interfaces.Block, prevBlockProof []byte) error {
if node.leanHelix == nil {
panic("ValidateBlockConsensus(): leanhelix is nil")
}
return node.leanHelix.ValidateBlockConsensus(ctx, block, blockProof, prevBlock, prevBlockProof, true)
}

func (node *Node) Sync(ctx context.Context, block interfaces.Block, blockProofBytes []byte, prevBlock interfaces.Block, prevBlockProofBytes []byte) error {
Expand Down
15 changes: 11 additions & 4 deletions workerloop.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (lh *WorkerLoop) handleUpdateState(receivedBlockWithProof *blockWithProof)
}
}

func (lh *WorkerLoop) ValidateBlockConsensus(ctx context.Context, block interfaces.Block, blockProofBytes []byte, prevBlock interfaces.Block, maybePrevBlockProofBytes []byte) error {
func (lh *WorkerLoop) ValidateBlockConsensus(ctx context.Context, block interfaces.Block, blockProofBytes []byte, prevBlock interfaces.Block, maybePrevBlockProofBytes []byte, softVerify bool) error {
if ctx.Err() != nil {
return errors.New("context canceled")
}
Expand Down Expand Up @@ -189,9 +189,16 @@ func (lh *WorkerLoop) ValidateBlockConsensus(ctx context.Context, block interfac
senderIds = append(senderIds, memberId)
}

isQuorum, sendersTotalWeight, q := quorum.IsQuorum(senderIds, committeeMembers)
if !isQuorum {
return errors.Errorf("ValidateBlockConsensus: sendersTotalWeight=%d is less than quorum=%d (committeeMembersCount=%d)", sendersTotalWeight, q, len(committeeMembers))
if softVerify {
hasHonest, sendersTotalWeight, b := quorum.HasHonest(senderIds, committeeMembers)
if !hasHonest { // not guaranteed (under f assumption) to have honest
return errors.Errorf("ValidateBlockConsensus: sendersTotalWeight=%d is not more than byz weight=%d (committeeMembersCount=%d)", sendersTotalWeight, b, len(committeeMembers))
}
} else {
isQuorum, sendersTotalWeight, q := quorum.IsQuorum(senderIds, committeeMembers)
if !isQuorum {
return errors.Errorf("ValidateBlockConsensus: sendersTotalWeight=%d is less than quorum=%d (committeeMembersCount=%d)", sendersTotalWeight, q, len(committeeMembers))
}
}

if len(blockProof.RandomSeedSignature()) == 0 || blockProof.RandomSeedSignature() == nil {
Expand Down

0 comments on commit bb44582

Please sign in to comment.