mirror of https://github.com/poanetwork/quorum.git
100 lines
3.0 KiB
Go
100 lines
3.0 KiB
Go
// Copyright 2017 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package core
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/istanbul"
|
|
)
|
|
|
|
func (c *core) sendPrepare() {
|
|
logger := c.logger.New("state", c.state)
|
|
|
|
sub := c.current.Subject()
|
|
encodedSubject, err := Encode(sub)
|
|
if err != nil {
|
|
logger.Error("Failed to encode", "subject", sub)
|
|
return
|
|
}
|
|
c.broadcast(&message{
|
|
Code: msgPrepare,
|
|
Msg: encodedSubject,
|
|
})
|
|
}
|
|
|
|
func (c *core) handlePrepare(msg *message, src istanbul.Validator) error {
|
|
// Decode PREPARE message
|
|
var prepare *Subject
|
|
err := msg.Decode(&prepare)
|
|
if err != nil {
|
|
return errFailedDecodePrepare
|
|
}
|
|
|
|
if err := c.checkMessage(msgPrepare, prepare.View); err != nil {
|
|
return err
|
|
}
|
|
|
|
// If it is locked, it can only process on the locked block.
|
|
// Passing verifyPrepare and checkMessage implies it is processing on the locked block since it was verified in the Preprepared state.
|
|
if err := c.verifyPrepare(prepare, src); err != nil {
|
|
return err
|
|
}
|
|
|
|
c.acceptPrepare(msg, src)
|
|
|
|
// Change to Prepared state if we've received enough PREPARE messages
|
|
// and we are in earlier state before Prepared state.
|
|
if (c.current.GetPrepareOrCommitSize() >= c.QuorumSize()) && c.state.Cmp(StatePrepared) < 0 {
|
|
|
|
// IBFT REDUX
|
|
c.current.preparedRound = c.currentView().Round
|
|
c.current.preparedBlock = prepare.Digest
|
|
c.PreparedRoundPrepares = c.current.Prepares
|
|
|
|
c.setState(StatePrepared)
|
|
c.sendCommit()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// verifyPrepare verifies if the received PREPARE message is equivalent to our subject
|
|
func (c *core) verifyPrepare(prepare *Subject, src istanbul.Validator) error {
|
|
logger := c.logger.New("from", src, "state", c.state)
|
|
|
|
sub := c.current.Subject()
|
|
if !reflect.DeepEqual(prepare.View, sub.View) || prepare.Digest.Hash().Hex() != sub.Digest.Hash().Hex() {
|
|
logger.Warn("Inconsistent subjects between PREPARE and proposal", "expected", sub, "got", prepare)
|
|
return errInconsistentSubject
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *core) acceptPrepare(msg *message, src istanbul.Validator) error {
|
|
logger := c.logger.New("from", src, "state", c.state)
|
|
|
|
// Add the PREPARE message to current round state
|
|
if err := c.current.Prepares.Add(msg); err != nil {
|
|
logger.Error("Failed to add PREPARE message to round state", "msg", msg, "err", err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|