consensus

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2019 License: MIT Imports: 20 Imported by: 0

README

SBA* Consensus

Intro

SBA is the first implementation of a novel consensus algorithm called Proof-Of-Blind-Bid, a privacy oriented, hybrid Proof-of-Stake like protocol with instant, statistical finality guarantees. The protocol is based on an Honest Majority of Money (an Adversary can corrupt nodes controlling up to f percent of the total stake value ≥ 3f + 1) and weak network synchrony assumptions.

The roles in the protocol are split between two different types: Block Generators and Provisioners. Block Generators retain their privacy, with the proofs of stake computed in zero-knowledge to preserve the anonymity of the Block Generator. On the other hand, Provisioners are required to deanonymize their stakes and remain transparent about their activities in the consensus while their stake remains valid.

Both bids and stakes have a registration period of t, which begins when a Bid or Stake transaction is included in a final block and is required to elapse before the full-node is eligible to participate in the consensus.

SBA protocol can be conceptually defined with an inner loop (Block Loop). Block Loop is responsible for reaching a consensus on a uniform block.

Security Model

The security model of SBA is based on Snow White, a provably secure Proof-of-Stake protocol. SBA is secure under a ∆-delayed mildly adaptive adversary (an adversary who is required to choose the nodes controlling a maximum of f percent of the total stake he/she is willing to corrupt ∆ rounds before the actual corruption) and in a weakly synchronous network with a propagation delay of up to δ seconds.

Block Generator

Block Generator is the first of the two full-node types eligible to participate in the consensus. To become a Block Generator, a full-node has to submit a Bid Transaction. The Block Generator is eligible to participate in one phase:

  • Block Generation

In the aforementioned phase, Block Generators participate in a non-interactive lottery to be able to forge a candidate block.

Provisioner

Provisioner is the second of the two full-node types eligible to participate in the consensus.

Unlike a Block Generator, a Provisioner node is required to deanonymize the value of the stake to be able to participate in the consensus. While it is technically possible to obfuscate the stake value, the team has decided against the latter as the addition of stake value obfuscation would have slowed down the consensus, and simultaneously increased the block size.

The Provisioner is eligible to participate in two phases:

  • Block Reduction
  • Block Agreement

The two mentioned phases are the way for Provisioners to reach consensus on a single block, which can then be added to the chain.

Values

Message Header
Field Type
pubkeyBLS BLS Signature
round uint64
step uint64
blockhash uint256

Redux-like architecture

The architecture for the implementation is based on a Flux or Redux like approach, where a single component holds the right to mutate the state, and any peripheral components/processes merely receive read-only copies of it. These peripheral components can request updates to the state, but the central Coordinator ultimately decides whether or not this state change will be enacted.

This Coordinator is accompanied by a roundStore which facilitates the dispatching of incoming events to other consensus components. As the Coordinator holds the single source of truth regarding consensus state, it redirects incoming events to the correct endpoint depending on their own state (included in the message header). The consensus components are then given the correct events, who apply further, more specific processing.

Event streaming

The Coordinator and roundStore are abstracted through the EventPlayer interface, exposing three methods:

  • Forward(id)
  • Play(id)
  • Pause(id)

Each method takes in a specific identifier, which should correspond to one of the Listeners saved on the roundStore. This ensures that requests are made by components which are considered valid.

Forward is a way for a component to request a state change, namely incrementing the step. If the given ID is found in the roundStore, the step is updated and returned to the caller. Play and Pause are used to enable or disable receiving of events from the Coordinator. This is mainly used for directing incoming events to the correct component in the case of multiple listeners, and for disconnecting consensus components when a round is finalized.

Event propagation

Since the Coordinator has full knowledge of the state, it is also responsible for signing outgoing messages. This functionality is abstracted through the Signer interface and exposes two methods:

  • Gossip(topic, hash, payload, id)
  • SendInternally(topic, hash, payload, id)

Both methods take an id, which allows the Coordinator to refuse requests for sending messages from obsolete components. Gossip is intended for propagation to the network, while SendInternally is intended for internal propagation.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DecodeRound added in v0.2.0

func DecodeRound(rb *bytes.Buffer, update *RoundUpdate) error

func InitAcceptedBlockUpdate

func InitAcceptedBlockUpdate(subscriber eventbus.Subscriber) (chan block.Block, eventbus.TopicListener)

InitAcceptedBlockUpdate init listener to get updates about lastly accepted block in the chain

func InitRoundUpdate

func InitRoundUpdate(subscriber eventbus.Subscriber) <-chan RoundUpdate

InitRoundUpdate initializes a Round update channel and fires up the TopicListener as well. Its purpose is to lighten up a bit the amount of arguments in creating the handler for the collectors. Also it removes the need to store subscribers on the consensus process

func LaunchNotification

func LaunchNotification(subscriber eventbus.Subscriber, deserializer wire.EventDeserializer, topic topics.Topic) <-chan wire.Event

func MockBidList added in v0.2.0

func MockBidList(amount int) user.BidList

func MockMember added in v0.2.0

func MockMember(keys key.ConsensusKeys) *user.Member

func MockProvisioners added in v0.2.0

func MockProvisioners(amount int) (*user.Provisioners, []key.ConsensusKeys)

func MockRoundUpdateBuffer added in v0.2.0

func MockRoundUpdateBuffer(round uint64, p *user.Provisioners, bidList user.BidList) *bytes.Buffer

Types

type AsyncState

type AsyncState struct {
	Round uint64
	Step  uint8
}

AsyncState is a representation of the consensus state at any given point in time. Can be used to 'date' messages that are passed between consensus components.

type Component added in v0.2.0

type Component interface {
	// Initialize a Component with data relevant to the current Round
	Initialize(EventPlayer, Signer, RoundUpdate) []TopicListener
	// Finalize allows a Component to perform cleanup operations before begin garbage collected
	Finalize()
	// ID allows the Coordinator to differentiate between components and
	// establish relevance or problems
	ID() uint32
}

Component is an ephemeral instance that lives solely for a round

type ComponentFactory added in v0.2.0

type ComponentFactory interface {
	// Instantiate a new Component without initializing it
	Instantiate() Component
}

ComponentFactory holds the data to create a Component (i.e. Signer, EventPublisher, RPCBus). Its responsibility is to recreate it on demand

type Coordinator added in v0.2.0

type Coordinator struct {
	*SyncState
	// contains filtered or unexported fields
}

Coordinator encapsulates the information about the Round and the Step of the coordinator. It also manages the roundStore, which aim is to centralize the state of the coordinator Component while decoupling them from each other and the EventBus

func Start added in v0.2.0

func Start(eventBus *eventbus.EventBus, keys key.ConsensusKeys, factories ...ComponentFactory) *Coordinator

Start the coordinator by wiring the listener to the RoundUpdate

func (*Coordinator) CollectEvent added in v0.2.0

func (c *Coordinator) CollectEvent(m bytes.Buffer) error

func (*Coordinator) CollectFinalize added in v0.2.0

func (c *Coordinator) CollectFinalize(m bytes.Buffer) error

CollectFinalize is triggered when the Agreement reaches quorum, and pre-emptively finalizes all consensus components, as they are no longer needed after this point.

func (*Coordinator) CollectRoundUpdate added in v0.2.0

func (c *Coordinator) CollectRoundUpdate(m bytes.Buffer) error

CollectRoundUpdate is triggered when the Chain propagates a new round update. The consensus components are swapped out, initialized, and the state will be updated to the new round.

func (*Coordinator) FinalizeRound added in v0.2.0

func (c *Coordinator) FinalizeRound()

func (*Coordinator) Forward added in v0.2.0

func (c *Coordinator) Forward(id uint32) uint8

func (*Coordinator) Gossip added in v0.2.0

func (c *Coordinator) Gossip(topic topics.Topic, hdr header.Header, payload *bytes.Buffer, id uint32) error

Gossip concatenates the topic, the header and the payload, and gossips it to the rest of the network.

func (*Coordinator) Pause added in v0.2.0

func (c *Coordinator) Pause(id uint32)

Pause event streaming for the listener with the specified ID.

func (*Coordinator) Play added in v0.2.0

func (c *Coordinator) Play(id uint32)

Play will resume event streaming for the listener with the specified ID.

func (*Coordinator) SendInternally added in v0.2.0

func (c *Coordinator) SendInternally(topic topics.Topic, hash []byte, payload *bytes.Buffer, id uint32) error

SendInternally prepends a header to the given payload, and publishes it on the desired topic.

func (*Coordinator) Sign added in v0.2.0

func (c *Coordinator) Sign(h header.Header) ([]byte, error)

XXX: adjust the signature verification on reduction (and agreement) Sign uses the blockhash (which is lost when decoupling the Header and the Payload) to recompose the Header and sign the Payload by adding it to the signature. Argument packet can be nil

func (*Coordinator) StopConsensus added in v0.2.0

func (c *Coordinator) StopConsensus(bytes.Buffer) error

type Event added in v0.2.0

type Event struct {
	Header  header.Header
	Payload bytes.Buffer
}

Event is the collection of a consensus message header and it's payload. Its primary purpose is to group all of the common fields in a consensus message together, and allow for consensus components to process the topic-specific payload on its own, while retaining the general information if needed.

func (Event) Equal added in v0.2.0

func (e Event) Equal(ev wire.Event) bool

Equal checks if an Event is equal to another.

func (Event) Sender added in v0.2.0

func (e Event) Sender() []byte

Sender returns the BLS public key of the event sender.

type EventPlayer added in v0.2.0

type EventPlayer interface {
	// Forward signals the Coordinator that a component wishes to further the step
	// of the consensus. An ID needs to be supplied in order for the Coordinator to
	// decide if this request is valid.
	Forward(uint32) uint8
	// Pause signals the Coordinator to temporarily pause Event forwarding for
	// a Listener specified through its ID.
	Pause(uint32)
	// Play resumes the Event forwarding for a Listener with the given ID.
	Play(uint32)
}

EventPlayer is the interface used by Components to signal their intention to get, pause or resume events for a given Step

type FilteringListener added in v0.2.0

type FilteringListener struct {
	*SimpleListener
	// contains filtered or unexported fields
}

FilteringListener is a Listener that performs filtering before triggering the callback specified by the component Normally it is used to filter out events sent by Provisioners not being part of a committee or invalid messages. Filtering is applied to the `header.Header`

func (*FilteringListener) NotifyPayload added in v0.2.0

func (cb *FilteringListener) NotifyPayload(ev Event) error

NotifyPayload uses the filtering function to let only relevant events through

type Listener added in v0.2.0

type Listener interface {
	// NotifyPayload forwards consensus events to the component
	NotifyPayload(Event) error
	// ID is used to later unsubscribe from the Coordinator. This is useful for components active throughout
	// multiple steps
	ID() uint32
	// Priority indicates the Priority of a Listener
	Priority() Priority
	Paused() bool
	Pause()
	Resume()
}

Listener subscribes to the Coordinator and forwards consensus events to the components

func NewFilteringListener added in v0.2.0

func NewFilteringListener(callback func(Event) error, filter func(header.Header) bool, priority Priority, paused bool) Listener

NewFilteringListener creates a FilteringListener

func NewSimpleListener added in v0.2.0

func NewSimpleListener(callback func(Event) error, priority Priority, paused bool) Listener

NewSimpleListener creates a SimpleListener

type Priority added in v0.2.0

type Priority uint8

Priority indicates a rough order among components subscribed to the same topic

const (
	// HighPriority indicates precedence
	HighPriority Priority = iota
	// LowPriority indicates that the component should be the last to get updates
	LowPriority
)

type Queue added in v0.2.0

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

Queue is a Queue of Events grouped by rounds and steps. It is threadsafe through a sync.RWMutex.

func NewQueue added in v0.2.0

func NewQueue() *Queue

NewQueue creates a new Queue. It is primarily used by Collectors to temporarily store messages not yet relevant to the collection process.

func (*Queue) Clear added in v0.2.0

func (eq *Queue) Clear(round uint64)

Clear the queue.

func (*Queue) Flush added in v0.2.0

func (eq *Queue) Flush(round uint64) []TopicEvent

Flush all events stored for a specific round from the queue, and return them.

func (*Queue) GetEvents added in v0.2.0

func (eq *Queue) GetEvents(round uint64, step uint8) []TopicEvent

GetEvents returns the events for a round and step.

func (*Queue) PutEvent added in v0.2.0

func (eq *Queue) PutEvent(round uint64, step uint8, m TopicEvent)

PutEvent stores an Event at a given round and step.

type Republisher

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

Republisher is responsible for gossiping a received event buffer.

func NewRepublisher

func NewRepublisher(publisher eventbus.Publisher, topic topics.Topic) *Republisher

NewRepublisher returns a Republisher containing the specified parameters.

func (*Republisher) Process

func (r *Republisher) Process(eventBuffer *bytes.Buffer) error

Process propagates a received event buffer to other nodes in the network.

type RoundUpdate added in v0.2.0

type RoundUpdate struct {
	Round   uint64
	P       user.Provisioners
	BidList user.BidList
	Seed    []byte
	Hash    []byte
}

roundCollector is a simple wrapper over a channel to get round notifications. It is not supposed to be used directly. Components interestesd in Round updates should use InitRoundUpdate instead

func MockRoundUpdate added in v0.2.0

func MockRoundUpdate(round uint64, p *user.Provisioners, bidList user.BidList) RoundUpdate

type Signer added in v0.2.0

type Signer interface {
	// Sign a payload. The first is parameter is a block hash
	Sign(header.Header) ([]byte, error)
	// Gossip concatenates all information before gossiping it to the
	// rest of the network.
	// It accepts a topic, a blockhash, a payload and the ID of the requesting
	// component
	Gossip(topics.Topic, header.Header, *bytes.Buffer, uint32) error
	// SendInternally is used for internal forwarding. It exposes the same
	// parameters as Gossip but does not perform a ED25519 signature
	// on the Event (and neither forwards it to the Gossip topic
	SendInternally(topics.Topic, []byte, *bytes.Buffer, uint32) error
}

Signer encapsulate the credentials to sign or authenticate outgoing events

type SimpleListener added in v0.2.0

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

SimpleListener implements Listener and uses a callback for notifying events

func (*SimpleListener) ID added in v0.2.0

func (s *SimpleListener) ID() uint32

ID returns the id to allow Component to unsubscribe

func (*SimpleListener) NotifyPayload added in v0.2.0

func (s *SimpleListener) NotifyPayload(ev Event) error

NotifyPayload triggers the callback specified during instantiation

func (*SimpleListener) Pause added in v0.2.0

func (s *SimpleListener) Pause()

func (*SimpleListener) Paused added in v0.2.0

func (s *SimpleListener) Paused() bool

func (*SimpleListener) Priority added in v0.2.0

func (s *SimpleListener) Priority() Priority

Priority as indicated by the Listener interface

func (*SimpleListener) Resume added in v0.2.0

func (s *SimpleListener) Resume()

type SimplePlayer added in v0.2.0

type SimplePlayer struct {
	Round uint64
	// contains filtered or unexported fields
}

SimplePlayer is used within tests to simulate the behaviour of the consensus.EventPlayer

func NewSimplePlayer added in v0.2.0

func NewSimplePlayer() *SimplePlayer

NewSimplePlayer creates a SimplePlayer

func (*SimplePlayer) Forward added in v0.2.0

func (s *SimplePlayer) Forward(uint32) uint8

Forward upticks the step

func (*SimplePlayer) Pause added in v0.2.0

func (s *SimplePlayer) Pause(id uint32)

Pause as specified by the EventPlayer interface

func (*SimplePlayer) Play added in v0.2.0

func (s *SimplePlayer) Play(id uint32)

Play as specified by the EventPlayer interface

func (*SimplePlayer) State added in v0.2.0

func (s *SimplePlayer) State() State

State s a threadsafe method to return whether the player is paused or not

func (*SimplePlayer) Step added in v0.2.0

func (s *SimplePlayer) Step() uint8

Step guards the step with a lock

type State

type State uint8

State indicates the status of the EventPlayer

const (
	// PAUSED player
	PAUSED State = iota
	// RUNNING player
	RUNNING
)

type SyncState

type SyncState struct {
	Lock sync.RWMutex
	// contains filtered or unexported fields
}

SyncState is an implementation of State which can be shared by multiple processes. It also notifies subscribers of changes in the state's step.

func NewState

func NewState() *SyncState

NewState returns an initialized SyncState.

func (*SyncState) IncrementStep

func (s *SyncState) IncrementStep()

IncrementStep increments the SyncState step by 1. It also notifies any subscribers of the state change.

func (*SyncState) Round

func (s *SyncState) Round() uint64

Round returns the round that the SyncState is on.

func (*SyncState) Step

func (s *SyncState) Step() uint8

Step returns the step that the SyncState is on.

func (*SyncState) String

func (s *SyncState) String() string

func (*SyncState) ToBuffer added in v0.2.0

func (s *SyncState) ToBuffer() bytes.Buffer

func (*SyncState) Update

func (s *SyncState) Update(round uint64)

Update the round of the SyncState.

type Threshold

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

Threshold is a number which proof scores should be compared against. If a proof score does not exceed the Threshold value, it should be discarded.

func NewThreshold

func NewThreshold() *Threshold

NewThreshold returns an initialized Threshold.

func (*Threshold) Exceeds

func (t *Threshold) Exceeds(score []byte) bool

Exceeds checks whether the Threshold exceeds a given score.

func (*Threshold) Lower

func (t *Threshold) Lower()

Lower the Threshold by cutting it in half.

func (*Threshold) Reset

func (t *Threshold) Reset()

Reset the Threshold to its normal lower limit.

type TopicEvent added in v0.2.0

type TopicEvent struct {
	Event
	Topic topics.Topic
}

TopicEvent is the concatenation of a consensus Event, and it's designated Topic.

func NewTopicEvent added in v0.2.0

func NewTopicEvent(topic topics.Topic, hdr header.Header, payload bytes.Buffer) TopicEvent

type TopicListener added in v0.2.0

type TopicListener struct {
	Listener
	Preprocessors []eventbus.Preprocessor
	Topic         topics.Topic
}

TopicListener is Listener carrying a Topic

Jump to

Keyboard shortcuts

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