consensus

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2019 License: MIT Imports: 25 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.

Event Driven Architecture

The consensus architecture is event-driven, chosen for its characteristics of allowing highly scalable applications while keeping the various architectural components highly decoupled and single-purposed. The various phases of the consensus are processed independently by single components, each subscribing to and publishing a variety of different events and payloads through multiple Topic Channels, implemented through the EventBus struct.

Broker Topology

According to the Broker Topology Strategy, each component is organized as a lightweight broker, where the event flow gets distributed across various sub-components in a chain-like fashion. This topology was chosen in order to keep the event processing flow relatively simple and to promote reusability of the different data structures and interfaces. The broker topology has the added benefit of preventing central event orchestration.

In our implementation of the broker topology, there are three main types of recurring architectural components:

- `Broker`: a federated struct that contains all the event channels used within the flow and which responsibility includes the creation and coordination of an `EventFilter`
- `EventFilter`: an entity receiving the _events_ and appointed to their validation, aggregation and processing
- one or more `channels` whereto the result of the processing get published

Additionally, several other entities are utilized within the EventFilter to help with code reuse and interface programming:

- `EventHandler`: This entity contains the logic specific to the components and that cannot be shared
- `EventQueue`: A temporary storage unit to collect messages referring to a future stage. This is possible given the asynchrony of the network which could result in nodes falling a bit behind in the event processing.
- `Processor`: An interface component which receives filtered messages from the `EventFilter`. It conducts additional checks, and stores the received event. The `Processor` only exposes one function, `Process`, which makes it simple to create multiple implementations which fit into the `EventFilter`.

Within the codebase, two implementations of the Processor currently exist:

- `Accumulator`: This component conducts additional checks on the received event, and then stores it in an `AccumulatorStore`, under an identifier which is extracted by the `EventHandler`. Once a set of events under one single identifier grows large enough, it is sent over a channel, and the `Accumulator` will clear itself for re-use.
- `Selector`: A component which verifies an incoming event, and only stores the 'best' event it has seen. The selector can return its current 'best' event at any point, after which it is cleared.

Common structures and interfaces

The consensus package exposes the function to create and initialize the most common channels reused across the whole package. The functions are defined as follows:

- InitRoundUpdate(eventbus) (chan uint64) returns a channel whereto round updates get published
- InitBlockRegeneratorCollector(eventbus) (chan AsyncState) returns a channel whose messages are interpreted as the `BLOCK_REGENERATION` signal, as outlined in the SBA* documentation.
- InitBidListUpdate(eventBus) (chan user.BidList) returns a channel on which BidLists are sent. They contain a collection of all X values, belonging to the blind bidders in the network. Any time this BidList is updated, it is propagated to all components which use it.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetStartingRound

func GetStartingRound(eventBroker wire.EventBroker, db database.DB, keys user.Keys) error

func InitAcceptedBlockUpdate

func InitAcceptedBlockUpdate(subscriber wire.EventSubscriber) (chan block.Block, *wire.TopicListener)

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

func InitBidListUpdate

func InitBidListUpdate(subscriber wire.EventSubscriber) chan user.Bid

InitBidListUpdate creates and initiates a channel for the updates in the BidList

func InitBlockRegenerationCollector

func InitBlockRegenerationCollector(subscriber wire.EventSubscriber) chan AsyncState

InitBlockRegenerationCollector initializes a regeneration channel, creates a regenerationCollector, and subscribes this collector to the BlockRegenerationTopic. The channel is then returned.

func InitRoundUpdate

func InitRoundUpdate(subscriber wire.EventSubscriber) <-chan uint64

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(eventbus wire.EventSubscriber, deserializer wire.EventDeserializer, topic string) <-chan wire.Event

func UpdateRound

func UpdateRound(bus wire.EventPublisher, round uint64)

UpdateRound is a shortcut for propagating a round

Types

type Accumulator

type Accumulator struct {
	WorkerTimeOut time.Duration
	wire.Store

	CollectedVotesChan chan []wire.Event
	// contains filtered or unexported fields
}

Accumulator is a generic event accumulator, that will accumulate events until it reaches a certain threshold.

func NewAccumulator

func NewAccumulator(handler AccumulatorHandler, store wire.Store, state State, checkStep bool) *Accumulator

NewAccumulator initializes a worker pool, starts up an Accumulator and returns it.

func (*Accumulator) Accumulate

func (a *Accumulator) Accumulate()

func (*Accumulator) CreateWorkers

func (a *Accumulator) CreateWorkers()

func (*Accumulator) Process

func (a *Accumulator) Process(ev wire.Event)

Process a received Event, by passing it to a worker in the worker pool (if the event sender is part of the voting committee).

type AccumulatorHandler

type AccumulatorHandler interface {
	EventHandler
	committee.Committee
	ExtractIdentifier(wire.Event, *bytes.Buffer) error
}

AccumulatorHandler is a generic event handler with some added functionality, that is specific to the accumulator.

type AccumulatorStore

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

AccumulatorStore is a helper struct for common operations on stored Event Arrays AccumulatorStore is an helper for common operations on stored Event Arrays

func NewAccumulatorStore

func NewAccumulatorStore() *AccumulatorStore

NewAccumulatorStore returns an initialized AccumulatorStore.

func (*AccumulatorStore) All

func (sec *AccumulatorStore) All() []wire.Event

All returns all of the Events currently in the AccumulatorStore.

func (*AccumulatorStore) Clear

func (sec *AccumulatorStore) Clear()

Clear up the AccumulatorStore.

func (*AccumulatorStore) Contains

func (sec *AccumulatorStore) Contains(event wire.Event, identifier string) bool

Contains checks if we already collected this event

func (*AccumulatorStore) Get

func (sec *AccumulatorStore) Get(identifier string) []wire.Event

Get a set of Events, stored under a specified identifier.

func (*AccumulatorStore) Insert

func (sec *AccumulatorStore) Insert(event wire.Event, identifier string) int

Insert the Event keeping track of the identifier (step, block hash, voted hash) it belongs to. It silently ignores duplicates (meaning it does not store an event in case it is already found at the identifier specified). It returns the number of events stored at specified identifier *after* the store operation

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 EventFilter

type EventFilter struct {
	Accumulator *Accumulator
	// contains filtered or unexported fields
}

EventFilter is a generic wire.Collector that can be used by consensus components for filtering and passing down messages. It coordinates an EventQueue to manage Events coming too early and delegates consensus specific logic to the handler.

func NewEventFilter

func NewEventFilter(handler AccumulatorHandler, state State, checkStep bool) *EventFilter

NewEventFilter returns an initialized EventFilter.

func (*EventFilter) Collect

func (ef *EventFilter) Collect(buffer *bytes.Buffer) error

Collect an event buffer, deserialize it, and then pass it to the proper component.

func (*EventFilter) FlushQueue

func (ef *EventFilter) FlushQueue()

FlushQueue will retrieve all queued events for a certain point in consensus, and hand them off to the Processor.

func (*EventFilter) ResetAccumulator

func (ef *EventFilter) ResetAccumulator()

func (*EventFilter) UpdateRound

func (ef *EventFilter) UpdateRound(round uint64)

UpdateRound updates the state for the EventFilter, and empties the queue of obsolete events.

type EventHandler

type EventHandler interface {
	wire.EventVerifier
	wire.EventMarshaller
	wire.EventDeserializer
	ExtractHeader(wire.Event) *header.Header
}

EventHandler encapsulates logic specific to the various EventFilters. Each EventFilter needs to verify, prioritize and extract information from Events. EventHandler is the interface that abstracts these operations away. The implementors of this interface is the real differentiator of the various consensus components

type EventQueue

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

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

func NewEventQueue

func NewEventQueue() *EventQueue

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

func (*EventQueue) Clear

func (eq *EventQueue) Clear(round uint64)

Clear the queue.

func (*EventQueue) Flush

func (eq *EventQueue) Flush(round uint64) []wire.Event

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

func (*EventQueue) GetEvents

func (eq *EventQueue) GetEvents(round uint64, step uint8) []wire.Event

GetEvents returns the events for a round and step.

func (*EventQueue) PutEvent

func (eq *EventQueue) PutEvent(round uint64, step uint8, m wire.Event)

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 wire.EventPublisher, topic topics.Topic) *Republisher

NewRepublisher returns a Republisher containing the specified parameters.

func (*Republisher) Process

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

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

type State

type State interface {
	fmt.Stringer
	Round() uint64
	Step() uint8
	SubscribeStep() *StepSubscriber
	Update(uint64)
	IncrementStep()
	Cmp(round uint64, step uint8) (int, int)
}

State comprises the methods to maintain a state of the consensus.

type StepSubscriber

type StepSubscriber struct {
	StateChan chan struct{}
	// contains filtered or unexported fields
}

StepSubscriber notifies its owner of a change in the state's step.

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) Cmp

func (s *SyncState) Cmp(round uint64, step uint8) (int, int)

Cmp returns negative number if the SyncState is in the future, 0 if they are the same and positive if the SyncState is in the past.

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) SubscribeStep

func (s *SyncState) SubscribeStep() *StepSubscriber

SubscribeStep returns a StepSubscriber which notifies its owner of a change in the state's step.

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 a passed score is higher or lower than the Threshold.

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 Timer

type Timer struct {
	TimeOutChan chan struct{}
	// contains filtered or unexported fields
}

func NewTimer

func NewTimer(timeOut time.Duration, timeOutChan chan struct{}) *Timer

func (*Timer) IncreaseTimeOut

func (t *Timer) IncreaseTimeOut()

func (*Timer) ResetTimeOut

func (t *Timer) ResetTimeOut()

func (*Timer) TimeOut

func (t *Timer) TimeOut() time.Duration

type Validator

type Validator struct{}

Validator is responsible for validating the Ed25519 signature of a message.

func (*Validator) Process

func (v *Validator) Process(buf *bytes.Buffer) (*bytes.Buffer, error)

Process a buffer by validating the ED25519 Signature. It uses a io.TeeReader to preserve the original message. It returns a copy of the message.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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