orderer

package
v0.0.0-...-7cd50c7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2023 License: Apache-2.0 Imports: 25 Imported by: 1

README

Orderer

The Orderer module implements the actual ordering of Batches, i.e., committing new Entries to the Log. The Orderer listens to the Manager for new Segments. Whenever the Manager issues a new Segment, the Orderer creates a new instance of the ordering protocol that proposes and agrees on Request Batches - one Batch for each SN that is part of the Segment. When a Batch has been agreed upon for a particular SN, the Orderer announces the (SN, Batch) pair as an Entry, indicating that it can be committed to the Log. We now describe the interface of an Orderer in terms of its behavior.

Execution of the Orderer

The Orderer module starts executing when its Start method is called by the system. The implementation of the Start method must:

  • Read Segments from the attached Manager (see below on initializing the Orderer).
  • For each obtained Segment, order the Segment (possibly in parallel with ordering other Segments).

We define ordering a Segment segment as calling announcer.Announce(logEntry) exactly once for each sequence number returned by segment.SNs. The logEntry parameter is of type *log.Entry and represents an Entry. It must contain one of the sequence numbers returned by segment.SNs along with a Batch of Requests.

Ordering a segment is subject to the following restrictions:

  • The set of logEntry arguments passed to invocations of announcer.Announce must be the same across all correct peers. (The order in which those Log Entries are announced, however, need not be the same.)
  • All Entries must contain Batches exclusively from the Segment's Bucket.
    • The leader of the protocol obtains a Batch using the segment.bucket.CutBatch method.
  • The leader must not call segment.bucket.CutBatch before a particular sequence number has been committed. This sequence number is defined by the Segment and accessible through the segment.StartsAfter method.
    • The log package provides a convenience method log.WaitForEntry that blocks until a specific Entry is committed.

Implementing an Orderer

To implement an Orderer, one must implement the orderer.Orderer interface. The Init, HandleMessage, and Start methods serve for integration with the rest of the system and their signature is described in the comments in orderer.go. Here we describe how these methods need to be implemented for obtaining a working Orderer.

For an example implementation of a dummy Orderer that can be used as a skeleton for real Orderer implementations, see orderer/dummyorderer.go.

Initializing the Orderer

Initialization needs to be implemented in the Init method. In addition to initializing whatever internal data structures the particular Orderer implementation needs, the Orderer must subscribe to Segments the provided Manager issues (the Manager is provided as an argument to Init). Subscribing to Segments will most likely be a one-liner calling the Manager's SubscribeOrderer method. This method returns a channel that the Orderer needs to save in its local state. When started, the Orderer will read Segments from the channel and order these Segments.

The Init method must be called before the Orderer is started (using Start). After Init returns, the Orderer must be ready to process incoming messages (even if the handler blocks on the first one), while not producing any outgoing messages. (Outgoing messages can be produced only after Start is called.) This is crucial, as the program that uses the Orderer firs initializes it and then starts the messaging subsystem (the Messenger). The Messenger needs an initialized Orderer for the messages the Messenger delivers. However, it is only after the Messenger starts, when it is safe for the Orderer to produce outgoing messages.

Protocol messages

As the Orderer is supposed to implement an ordering protocol, it will need to exchange messages. Each message used by the Orderer is wrapped in a protocol message of type *pb.OrdererMsg, defined in protobufs/messenger.proto. A *pb.OrdererMsg only has one field (called Msg) of the protocol buffers "oneof" type, containing the actual message of the ordering protocol. The Orderer implementation must define its own message types (e.g. PrePrepare, Prepare, Commit, etc. for PBFT) to be used in this field and add these message types as possible values of the msg field in the definition of OrdererMsg in protobufs/messenger.proto.

Sending messages

To send a message m to a peer with ID id, the Orderer implementation only needs to call the messenger.EnqueueMessage(m, id). The message m needs to be of type *pb.ProtocolMessage with senderId set to the own ID (accessible through membership.OwnID) and Msg containing a (properly wrapped) message of type *pb.OrdererMsg. The OrdererMsg, in turn, contains the (properly wrapped) actual message in its own (nested) Msg field.

For example, the DummyOrderer defines a DummyOrdererMsg, an instance of which is created as follows.

m := &pb.ProtocolMessage{
    SenderId: membership.OwnID,
    Msg: &pb.ProtocolMessage_Orderer{Orderer: &pb.OrdererMsg{
        Msg: &pb.OrdererMsg_Dummy{Dummy:&pb.DummyOrdererMsg{
            ProtocolSpedificField1: protocolSpecificValue1
            ProtocolSpedificField2: protocolSpecificValue2
            //...
        }},
    }},
}
Handling messages

To handle incoming messages, the HandleMessage method of the Orderer must be implemented. This method is called by the Messenger whenever the peer receives a message that belongs to the ordering protocol. Note that HandleMessage will potentially be called by multiple goroutines concurrently and its implementation needs to deal with it.

In addition to the received message, HandleMessage receives he ID of the sending peer as an additional argument. Depending on the implementation of Messenger, thes messages might or might not be authenticated.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DummyOrderer

type DummyOrderer struct {
	// contains filtered or unexported fields
}

Represents a dummy Orderer implementation (a stub). For each sequence number in each Segment received from the Manager, the leader (defined to be the first node in the Segment's leader list, never changes) sends a single message with dummy data to the followers. A follower receiving such a message directly announces a log Entry with that data as the decision for that sequence number.

func (*DummyOrderer) CheckSig

func (do *DummyOrderer) CheckSig(data []byte, senderID int32, signature []byte) error

func (*DummyOrderer) HandleEntry

func (do *DummyOrderer) HandleEntry(entry *log.Entry)

func (*DummyOrderer) HandleMessage

func (do *DummyOrderer) HandleMessage(msg *pb.ProtocolMessage)

This function is called by the messenger each time an Orderer-issued message is received over the network. DummyOrderer only knows one such message, through which the leader proposes a decision for a sequence number. DummyOrderer directly announces the contents of the message as the decision, removing the corresponding requests from the Bucket of pending requests.

func (*DummyOrderer) Init

func (do *DummyOrderer) Init(mngr manager.Manager)

Initializes the DummyOrderer by subscribing to new segments issued by the Manager.

func (*DummyOrderer) Sign

func (do *DummyOrderer) Sign(data []byte) ([]byte, error)

func (*DummyOrderer) Start

func (do *DummyOrderer) Start(wg *sync.WaitGroup)

Starts the DummyOrderer. Listens on the channel where the Manager issues new Segemnts and starts a goroutine to handle each of them. Meant to be run as a separate goroutine. Decrements the provided wait group when done.

type HotStuffOrderer

type HotStuffOrderer struct {
	// contains filtered or unexported fields
}

Represents a HotStuff Orderer implementation.

func (*HotStuffOrderer) AssembleCert

func (ho *HotStuffOrderer) AssembleCert(data []byte, signatures [][]byte) ([]byte, error)

AssembleCert combines validates signature shares in a threshold signature. A threshold signature form the quorum certificate.

func (*HotStuffOrderer) CheckCert

func (ho *HotStuffOrderer) CheckCert(data []byte, signature []byte) error

CheckCert checks if the certificate is a valid threshold signature

func (*HotStuffOrderer) CheckSig

func (ho *HotStuffOrderer) CheckSig(data []byte, senderID int32, signature []byte) error

CheckSig checks if a signature share is valid.

func (*HotStuffOrderer) HandleEntry

func (ho *HotStuffOrderer) HandleEntry(entry *log.Entry)

func (*HotStuffOrderer) HandleMessage

func (ho *HotStuffOrderer) HandleMessage(msg *pb.ProtocolMessage)

HandleMessage is called by the messenger each time an Orderer-issued message is received over the network.

func (*HotStuffOrderer) Init

func (ho *HotStuffOrderer) Init(mngr manager.Manager)

func (*HotStuffOrderer) Sign

func (ho *HotStuffOrderer) Sign(data []byte) ([]byte, error)

Sign generates a signature share.

func (*HotStuffOrderer) Start

func (ho *HotStuffOrderer) Start(wg *sync.WaitGroup)

Starts the HotStuff orderer. Listens on the channel where the Manager issues new Segemnts and starts a goroutine to handle each of them. Meant to be run as a separate goroutine. Decrements the provided wait group when done.

type Instance

type Instance interface {
	// contains filtered or unexported methods
}

type Orderer

type Orderer interface {

	// Initializes the orderer.
	// Attaches a Manager to the Orderer. All the Segments that are created by the Manager and in which this node is
	// involved (as a leader, as a follower, or both) will be handled by this Orderer.
	// Init() must be called before the Manager is started, so the Orderer does not miss any segments.
	// Init() must be called before Strat() is called.
	// After Init() returns, the Orderer mus be ready to process incoming messages, but must not send any itself
	// (sending messages only can start after the call to Start()).
	Init(manager manager.Manager)

	// Message handler function. To be assigned to the messenger.OrdererMsgHandler variable, which the messenger calls
	// on reception of a message belonging to the ordering subprotocol.
	HandleMessage(message *pb.ProtocolMessage)

	// Must be called when an entry is being inserted to the log otherwise than by the orderer itself,
	// e.g. by the state transfer protocol.
	HandleEntry(entry *log.Entry)

	// Satrts the Orderer. Meant to be run as a separate goroutine. Decrements the passed wait group on termination.
	// Before starting the Orderer, it must be attached to the Manager and its message handler must be registered with
	// the messanger.
	Start(group *sync.WaitGroup)

	// Signs the data with the private key (share) of the orderer.
	Sign(data []byte) ([]byte, error)

	// Verifies that the signature on the (unhashed) data with public key of the sender is correct.
	// SenderID must correspond to an orderer, whose key is known in system's membership config.
	CheckSig(data []byte, senderID int32, signature []byte) error
}

The Orderer is responsible for ordering log Entries, i.e., creating the mapping between Entries and sequence numbers. It receives Segments (representing parts of the log) from the Manager and "fills" these parts of the log with Entries. The Orderer can process multiple Segments in parallel, executing multiple instances of an ordering protocol (or even different protocols) - one for each Segment. When a (final and irreversible) assignment of an Entry to a sequence number is made by the ordering protocol, the protocol calls announcer.Announce() to announce the decision.

type PbftOrderer

type PbftOrderer struct {
	// contains filtered or unexported fields
}

Represents a PBFT Orderer implementation.

func (*PbftOrderer) AssembleCert

func (ho *PbftOrderer) AssembleCert(data []byte, signatures [][]byte, ids [][]byte) ([]byte, error)

AssembleCert combines validates signature shares in a threshold signature. A threshold signature form the quorum certificate.

func (*PbftOrderer) CheckCert

func (ho *PbftOrderer) CheckCert(data []byte, signature []byte) error

CheckCert checks if the certificate is a valid threshold signature

func (*PbftOrderer) CheckSig

func (ho *PbftOrderer) CheckSig(data []byte, senderID int32, signature []byte) error

CheckSig checks if a signature share is valid.

func (*PbftOrderer) CheckSigShare

func (ho *PbftOrderer) CheckSigShare(data []byte, k int32, signature []byte) error

CheckSigShare checks if a signature share is valid.

func (*PbftOrderer) CompareSig

func (ho *PbftOrderer) CompareSig(sig1 []byte, sig2 []byte) bool

func (*PbftOrderer) DesIdToString

func (ho *PbftOrderer) DesIdToString(id []byte) string

func (*PbftOrderer) HandleEntry

func (po *PbftOrderer) HandleEntry(entry *log.Entry)

Handles entries produced externally.

func (*PbftOrderer) HandleMessage

func (po *PbftOrderer) HandleMessage(msg *pb.ProtocolMessage)

HandleMessage is called by the messenger each time an Orderer-issued message is received over the network.

func (*PbftOrderer) Init

func (po *PbftOrderer) Init(mngr manager.Manager)

Initializes the PbftOrderer. Subscribes to new segments issued by the Manager and allocates internal buffers and data structures.

func (*PbftOrderer) Sign

func (ho *PbftOrderer) Sign(data []byte) ([]byte, error)

Sign generates a signature share. k represent the k th private key the peer use.

func (*PbftOrderer) SignWithKthKey

func (ho *PbftOrderer) SignWithKthKey(data []byte, k int32) ([]byte, []byte, error)

Sign generates a signature share. k represent the k th private key the peer use.

func (*PbftOrderer) Start

func (po *PbftOrderer) Start(wg *sync.WaitGroup)

Starts the PbftOrderer. Listens on the channel where the Manager issues new Segemnts and starts a goroutine to handle each of them. Meant to be run as a separate goroutine. Decrements the provided wait group when done.

type RaftOrderer

type RaftOrderer struct {
	// contains filtered or unexported fields
}

func (*RaftOrderer) CheckSig

func (ro *RaftOrderer) CheckSig(data []byte, senderID int32, signature []byte) error

func (*RaftOrderer) HandleEntry

func (ro *RaftOrderer) HandleEntry(entry *log.Entry)

func (*RaftOrderer) HandleMessage

func (ro *RaftOrderer) HandleMessage(msg *pb.ProtocolMessage)

HandleMessage is called by the messenger each time an Orderer-issued message is received over the network.

func (*RaftOrderer) Init

func (ro *RaftOrderer) Init(mngr manager.Manager)

Init initializes the Raft orderer. Subscribes to new segments issued by the Manager and allocates internal buffers and data structures.

func (*RaftOrderer) Sign

func (ro *RaftOrderer) Sign(data []byte) ([]byte, error)

func (*RaftOrderer) Start

func (ro *RaftOrderer) Start(wg *sync.WaitGroup)

Start starts the Raft orderer. Listens on the channel where the Manager issues new segments and starts a goroutine to handle each of them. Meant to be run as a separate goroutine. Decrements the provided wait group when done.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL