quorum/consensus/istanbul/core/types.go

181 lines
4.3 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 (
"bytes"
"fmt"
"io"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
type Engine interface {
Start() error
Stop() error
IsProposer() bool
// verify if a hash is the same as the proposed block in the current pending request
//
// this is useful when the engine is currently the proposer
//
// pending request is populated right at the preprepare stage so this would give us the earliest verification
// to avoid any race condition of coming propagated blocks
IsCurrentProposal(blockHash common.Hash) bool
}
type State uint64
const (
StateAcceptRequest State = iota
StatePreprepared
StatePrepared
StateCommitted
)
func (s State) String() string {
if s == StateAcceptRequest {
return "Accept request"
} else if s == StatePreprepared {
return "Preprepared"
} else if s == StatePrepared {
return "Prepared"
} else if s == StateCommitted {
return "Committed"
} else {
return "Unknown"
}
}
// Cmp compares s and y and returns:
// -1 if s is the previous state of y
// 0 if s and y are the same state
// +1 if s is the next state of y
func (s State) Cmp(y State) int {
if uint64(s) < uint64(y) {
return -1
}
if uint64(s) > uint64(y) {
return 1
}
return 0
}
const (
msgPreprepare uint64 = iota
msgPrepare
msgCommit
msgRoundChange
// msgAll
)
type message struct {
Code uint64
Msg []byte
Address common.Address
Signature []byte
CommittedSeal []byte
}
// ==============================================
//
// define the functions that needs to be provided for rlp Encoder/Decoder.
// EncodeRLP serializes m into the Ethereum RLP format.
func (m *message) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, []interface{}{m.Code, m.Msg, m.Address, m.Signature, m.CommittedSeal})
}
// DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
func (m *message) DecodeRLP(s *rlp.Stream) error {
var msg struct {
Code uint64
Msg []byte
Address common.Address
Signature []byte
CommittedSeal []byte
}
if err := s.Decode(&msg); err != nil {
return err
}
m.Code, m.Msg, m.Address, m.Signature, m.CommittedSeal = msg.Code, msg.Msg, msg.Address, msg.Signature, msg.CommittedSeal
return nil
}
// ==============================================
//
// define the functions that needs to be provided for core.
func (m *message) FromPayload(b []byte, validateFn func([]byte, []byte) (common.Address, error)) error {
// Decode message
err := rlp.DecodeBytes(b, &m)
if err != nil {
return err
}
// Validate message (on a message without Signature)
if validateFn != nil {
var payload []byte
payload, err = m.PayloadNoSig()
if err != nil {
return err
}
signerAdd, err := validateFn(payload, m.Signature)
if err != nil {
return err
}
if !bytes.Equal(signerAdd.Bytes(), m.Address.Bytes()) {
return errInvalidSigner
}
}
return nil
}
func (m *message) Payload() ([]byte, error) {
return rlp.EncodeToBytes(m)
}
func (m *message) PayloadNoSig() ([]byte, error) {
return rlp.EncodeToBytes(&message{
Code: m.Code,
Msg: m.Msg,
Address: m.Address,
Signature: []byte{},
CommittedSeal: m.CommittedSeal,
})
}
func (m *message) Decode(val interface{}) error {
return rlp.DecodeBytes(m.Msg, val)
}
func (m *message) String() string {
return fmt.Sprintf("{Code: %v, Address: %v}", m.Code, m.Address.String())
}
// ==============================================
//
// helper functions
func Encode(val interface{}) ([]byte, error) {
return rlp.EncodeToBytes(val)
}