Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
goran-ethernal committed Jun 27, 2024
1 parent e81a63f commit c43fd6b
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 222 deletions.
59 changes: 9 additions & 50 deletions core/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -1032,56 +1032,15 @@ func (i *IBFT) buildProposal(ctx context.Context, view *proto.View) *proto.IbftM
return nil
}

// check the messages for any previous proposal (if they have any, it's the same proposal)
var (
previousProposal []byte
maxRound uint64
)

// take previous proposal among the round change messages for the highest round
for _, msg := range rcc.RoundChangeMessages {
latestPC := messages.ExtractLatestPC(msg)
if latestPC == nil {
continue
}

proposal := messages.ExtractProposal(latestPC.ProposalMessage)
preparedCertificateRound := proposal.Round

// skip if message's round is equals to/less than maxRound
if previousProposal != nil && preparedCertificateRound <= maxRound {
continue
}

lastPB := messages.ExtractLastPreparedProposal(msg)
if lastPB == nil {
continue
}

previousProposal = lastPB.RawProposal
maxRound = preparedCertificateRound
}

if previousProposal == nil {
// build new proposal
proposal := i.backend.BuildProposal(
&proto.View{
Height: height,
Round: round,
})

return i.backend.BuildPrePrepareMessage(
proposal,
rcc,
&proto.View{
Height: height,
Round: round,
},
)
}
// build always new proposal
proposal := i.backend.BuildProposal(
&proto.View{
Height: height,
Round: round,
})

return i.backend.BuildPrePrepareMessage(
previousProposal,
proposal,
rcc,
&proto.View{
Height: height,
Expand Down Expand Up @@ -1239,8 +1198,8 @@ func (i *IBFT) sendPreprepareMessage(message *proto.IbftMessage) {
func (i *IBFT) sendRoundChangeMessage(height, newRound uint64) {
i.transport.Multicast(
i.backend.BuildRoundChangeMessage(
i.state.getLatestPreparedProposal(),
i.state.getLatestPC(),
nil,
nil,
&proto.View{
Height: height,
Round: newRound,
Expand Down
172 changes: 0 additions & 172 deletions core/ibft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,178 +424,6 @@ func TestRunNewRound_Proposer(t *testing.T) {
assert.Nil(t, multicastedPrepare)
},
)

t.Run(
"proposer builds proposal for round > 0 (resend last prepared proposal)",
func(t *testing.T) {
t.Parallel()

lastPreparedProposedProposal := &proto.Proposal{
RawProposal: []byte("dummy block"),
Round: 0,
}

quorum := uint64(4)
ctx, cancelFn := context.WithCancel(context.Background())

roundChangeMessages := generateMessagesWithUniqueSender(quorum, proto.MessageType_ROUND_CHANGE)
prepareMessages := generateMessages(quorum-1, proto.MessageType_PREPARE)

for index, message := range prepareMessages {
message.Payload = &proto.IbftMessage_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: correctRoundMessage.hash,
},
}

message.From = []byte(fmt.Sprintf("node %d", index+1))
}

setRoundForMessages(roundChangeMessages, 1)

// Make sure at least one RC message has a PC
payload, _ := roundChangeMessages[1].Payload.(*proto.IbftMessage_RoundChangeData)
rcData := payload.RoundChangeData

rcData.LastPreparedProposal = lastPreparedProposedProposal
rcData.LatestPreparedCertificate = &proto.PreparedCertificate{
ProposalMessage: &proto.IbftMessage{
View: &proto.View{
Height: 0,
Round: 0,
},
From: []byte("unique node"),
Type: proto.MessageType_PREPREPARE,
Payload: &proto.IbftMessage_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
Proposal: lastPreparedProposedProposal,
ProposalHash: correctRoundMessage.hash,
Certificate: nil,
},
},
},
PrepareMessages: prepareMessages,
}

var (
proposerID = []byte("unique node")
multicastedPreprepare *proto.IbftMessage = nil
multicastedPrepare *proto.IbftMessage = nil
proposal = []byte("proposal")
notifyCh = make(chan uint64, 1)

log = mockLogger{}
transport = mockTransport{func(message *proto.IbftMessage) {
switch message.Type {
case proto.MessageType_PREPREPARE:
multicastedPreprepare = message
case proto.MessageType_PREPARE:
multicastedPrepare = message
default:
}
}}
backend = mockBackend{
idFn: func() []byte { return proposerID },
isProposerFn: func(proposer []byte, _ uint64, _ uint64) bool {
return bytes.Equal(proposerID, proposer)
},
getVotingPowerFn: testCommonGetVotingPowertFnForCnt(quorum),
buildProposalFn: func(_ uint64) []byte {
return proposal
},
buildPrepareMessageFn: func(_ []byte, view *proto.View) *proto.IbftMessage {
return &proto.IbftMessage{
View: view,
Type: proto.MessageType_PREPARE,
Payload: &proto.IbftMessage_PrepareData{
PrepareData: &proto.PrepareMessage{
ProposalHash: correctRoundMessage.hash,
},
},
}
},
buildPrePrepareMessageFn: func(
rawProposal []byte,
certificate *proto.RoundChangeCertificate,
view *proto.View,
) *proto.IbftMessage {
return &proto.IbftMessage{
View: view,
Type: proto.MessageType_PREPREPARE,
Payload: &proto.IbftMessage_PreprepareData{
PreprepareData: &proto.PrePrepareMessage{
Proposal: &proto.Proposal{
RawProposal: rawProposal,
Round: 0,
},
ProposalHash: correctRoundMessage.hash,
Certificate: certificate,
},
},
}
},
}
messages = mockMessages{
subscribeFn: func(_ messages.SubscriptionDetails) *messages.Subscription {
return &messages.Subscription{
ID: messages.SubscriptionID(1),
SubCh: notifyCh,
}
},
unsubscribeFn: func(_ messages.SubscriptionID) {
cancelFn()
},
getValidMessagesFn: func(
view *proto.View,
messageType proto.MessageType,
isValid func(message *proto.IbftMessage) bool,
) []*proto.IbftMessage {
return filterMessages(
roundChangeMessages,
isValid,
)
},
getExtendedRCCFn: func(
height uint64,
isValidMessage func(message *proto.IbftMessage) bool,
isValidRCC func(round uint64, messages []*proto.IbftMessage) bool,
) []*proto.IbftMessage {
return filterMessages(
roundChangeMessages,
isValidMessage,
)
},
}
)

i := NewIBFT(log, backend, transport)
require.NoError(t, i.validatorManager.Init(0))
i.messages = messages
i.state.setView(&proto.View{
Height: 0,
Round: 1,
})

notifyCh <- 1

i.wg.Add(1)
i.startRound(ctx)

i.wg.Wait()

// Make sure the node changed the state to prepare
assert.Equal(t, prepare, i.state.name)

// Make sure the multicasted proposal is the accepted proposal
assert.Equal(t, multicastedPreprepare, i.state.proposalMessage)

// Make sure the correct proposal was multicasted
assert.True(t, proposalMatches(lastPreparedProposedProposal, multicastedPreprepare))

// Make sure the prepare message was not multicasted
assert.Nil(t, multicastedPrepare)
},
)
}

// TestRunNewRound_Validator_Zero validates the behavior
Expand Down

0 comments on commit c43fd6b

Please sign in to comment.