Skip to content

Commit

Permalink
Checking PC validity performance improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
stana-miric committed Oct 6, 2023
1 parent 628065c commit 2b25997
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 79 deletions.
24 changes: 2 additions & 22 deletions core/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -1161,11 +1161,6 @@ func (i *IBFT) validPC(
certificate.PrepareMessages...,
)

// Make sure the senders are unique
if !messages.HasUniqueSenders(allMessages) {
return false
}

// Make sure there are at least Quorum (PP + P) messages
// hasQuorum directly since the messages are of different types
if !i.validatorManager.HasQuorum(convertMessageToAddressSet(allMessages)) {
Expand All @@ -1184,23 +1179,8 @@ func (i *IBFT) validPC(
}
}

// Make sure the proposal hashes match
if !messages.HaveSameProposalHash(allMessages) {
return false
}

// Make sure all the messages have a round number lower than rLimit
if !messages.AllHaveLowerRound(allMessages, rLimit) {
return false
}

// Make sure all the messages have the same height
if !messages.AllHaveSameHeight(allMessages, height) {
return false
}

// Make sure all have the same round
if !messages.AllHaveSameRound(allMessages) {
// Make sure the round, height and proposal hashes match and the senders are unique
if !messages.AreValidPCMessages(allMessages, height, rLimit) {
return false
}

Expand Down
81 changes: 29 additions & 52 deletions messages/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,86 +141,63 @@ func HasUniqueSenders(messages []*proto.Message) bool {
return true
}

// HaveSameProposalHash checks if the messages have the same proposal hash
func HaveSameProposalHash(messages []*proto.Message) bool {
// AreValidPCMessages validates PreparedCertificate messages
func AreValidPCMessages(messages []*proto.Message, height uint64, roundLimit uint64) bool {
if len(messages) < 1 {
return false
}

round := messages[0].View.Round
senderMap := make(map[string]struct{})

var hash []byte

for _, message := range messages {
var extractedHash []byte

switch message.Type {
case proto.MessageType_PREPREPARE:
extractedHash = ExtractProposalHash(message)
case proto.MessageType_PREPARE:
extractedHash = ExtractPrepareHash(message)
case proto.MessageType_COMMIT, proto.MessageType_ROUND_CHANGE:
// all messages must have the same height
if message.View.Height != height {
return false
default:
}

// all messages must have the same round that is not greater than rount limit
if message.View.Round != round || message.View.Round >= roundLimit {
return false
}

// all messages must have the same proposal hash
extractedHash, ok := extractPCMessageHash(message)
if hash == nil {
// No previous hash for comparison,
// set the first one as the reference, as
// all of them need to be the same anyway
hash = extractedHash
}

if !bytes.Equal(hash, extractedHash) {
if !ok || !bytes.Equal(hash, extractedHash) {
return false
}
}

return true
}

// AllHaveLowerRound checks if all messages have the same round
func AllHaveLowerRound(messages []*proto.Message, round uint64) bool {
if len(messages) < 1 {
return false
}

for _, message := range messages {
if message.View.Round >= round {
// all messages must have unique senders
key := string(message.From)
if _, exists := senderMap[key]; exists {
return false
}
}

return true
}

// AllHaveSameRound checks if all messages have the same round
func AllHaveSameRound(messages []*proto.Message) bool {
if len(messages) < 1 {
return false
}

var round = messages[0].View.Round

for _, message := range messages {
if message.View.Round != round {
return false
}
senderMap[key] = struct{}{}
}

return true
}

// AllHaveSameHeight checks if all messages have the same height
func AllHaveSameHeight(messages []*proto.Message, height uint64) bool {
if len(messages) < 1 {
return false
// extractPCMessageHash extracts the hash from a PC message
func extractPCMessageHash(message *proto.Message) ([]byte, bool) {
switch message.Type {
case proto.MessageType_PREPREPARE:
return ExtractProposalHash(message), true
case proto.MessageType_PREPARE:
return ExtractPrepareHash(message), true
case proto.MessageType_COMMIT, proto.MessageType_ROUND_CHANGE:
return nil, false
default:
return nil, false
}

for _, message := range messages {
if message.View.Height != height {
return false
}
}

return true
}
109 changes: 104 additions & 5 deletions messages/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/0xPolygon/go-ibft/messages/proto"
)

var proposalHash = []byte("proposal hash")

func TestMessages_ExtractCommittedSeals(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -467,8 +469,6 @@ func TestMessages_HasUniqueSenders(t *testing.T) {
func TestMessages_HaveSameProposalHash(t *testing.T) {
t.Parallel()

proposalHash := []byte("proposal hash")

testTable := []struct {
name string
messages []*proto.Message
Expand All @@ -484,6 +484,11 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
[]*proto.Message{
{
Type: proto.MessageType_ROUND_CHANGE,
View: &proto.View{
Height: 1,
Round: 1,
},
From: []byte("node 1"),
},
},
false,
Expand All @@ -498,6 +503,11 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
ProposalHash: proposalHash,
},
},
View: &proto.View{
Height: 1,
Round: 1,
},
From: []byte("node 1"),
},
{
Type: proto.MessageType_PREPARE,
Expand All @@ -506,6 +516,11 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
ProposalHash: []byte("differing hash"),
},
},
View: &proto.View{
Height: 1,
Round: 1,
},
From: []byte("node 2"),
},
},
false,
Expand All @@ -520,6 +535,11 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
ProposalHash: proposalHash,
},
},
View: &proto.View{
Height: 1,
Round: 1,
},
From: []byte("node 1"),
},
{
Type: proto.MessageType_PREPARE,
Expand All @@ -528,6 +548,11 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
ProposalHash: proposalHash,
},
},
View: &proto.View{
Height: 1,
Round: 1,
},
From: []byte("node 2"),
},
},
true,
Expand All @@ -543,7 +568,7 @@ func TestMessages_HaveSameProposalHash(t *testing.T) {
assert.Equal(
t,
testCase.haveSame,
HaveSameProposalHash(testCase.messages),
AreValidPCMessages(testCase.messages, 1, 2),
)
})
}
Expand Down Expand Up @@ -574,12 +599,26 @@ func TestMessages_AllHaveLowerRond(t *testing.T) {
Height: 0,
Round: round,
},
Type: proto.MessageType_PREPREPARE,
Payload: &proto.Message_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 1"),
},
{
View: &proto.View{
Height: 0,
Round: round + 1,
},
Type: proto.MessageType_PREPARE,
Payload: &proto.Message_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 2"),
},
},
round,
Expand All @@ -593,12 +632,26 @@ func TestMessages_AllHaveLowerRond(t *testing.T) {
Height: 0,
Round: round + 1,
},
Type: proto.MessageType_PREPREPARE,
Payload: &proto.Message_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 1"),
},
{
View: &proto.View{
Height: 0,
Round: round + 1,
},
Type: proto.MessageType_PREPARE,
Payload: &proto.Message_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 2"),
},
},
round,
Expand All @@ -612,12 +665,26 @@ func TestMessages_AllHaveLowerRond(t *testing.T) {
Height: 0,
Round: round,
},
Type: proto.MessageType_PREPREPARE,
Payload: &proto.Message_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 1"),
},
{
View: &proto.View{
Height: 0,
Round: round,
},
Type: proto.MessageType_PREPARE,
Payload: &proto.Message_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 2"),
},
},
2,
Expand All @@ -634,8 +701,9 @@ func TestMessages_AllHaveLowerRond(t *testing.T) {
assert.Equal(
t,
testCase.haveLower,
AllHaveLowerRound(
AreValidPCMessages(
testCase.messages,
0,
testCase.round,
),
)
Expand Down Expand Up @@ -665,11 +733,25 @@ func TestMessages_AllHaveSameHeight(t *testing.T) {
View: &proto.View{
Height: height - 1,
},
Type: proto.MessageType_PREPREPARE,
Payload: &proto.Message_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 1"),
},
{
View: &proto.View{
Height: height,
},
Type: proto.MessageType_PREPARE,
Payload: &proto.Message_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 2"),
},
},
false,
Expand All @@ -680,12 +762,28 @@ func TestMessages_AllHaveSameHeight(t *testing.T) {
{
View: &proto.View{
Height: height,
Round: 1,
},
Type: proto.MessageType_PREPREPARE,
Payload: &proto.Message_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 1"),
},
{
View: &proto.View{
Height: height,
Round: 1,
},
Type: proto.MessageType_PREPARE,
Payload: &proto.Message_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: proposalHash,
},
},
From: []byte("node 2"),
},
},
true,
Expand All @@ -701,9 +799,10 @@ func TestMessages_AllHaveSameHeight(t *testing.T) {
assert.Equal(
t,
testCase.haveSame,
AllHaveSameHeight(
AreValidPCMessages(
testCase.messages,
height,
2,
),
)
})
Expand Down

0 comments on commit 2b25997

Please sign in to comment.