hbbft

package module
v0.0.0-...-0826ffd Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2019 License: MIT Imports: 12 Imported by: 1

README

hbbft Releases Build Status Report Card

Practical implementation of the Honey Badger Byzantine Fault Tolerance consensus algorithm written in Go.

Summary

This package includes the building blocks for implementing a practical version of the hbbft protocol. The exposed engine can be plugged easily into existing applications. Users can choose to use the transport layer or roll their own. For implementation details take a look at the simulations which implements hbbft into a realistic scenario. The building blocks of hbbft exist out of the following sub-protocols:

Reliable broadcast (RBC)

Uses reedsolomon erasure encoding to disseminate an ecrypted set of transactions.

Binary Byzantine Agreement (BBA)

Uses a common coin to agree that a majority of the participants have a consensus that RBC has completed.

Asynchronous Common Subset (ACS)

Combines RBC and BBA to agree on a set of encrypted transactions.

HoneyBadger

Top level HoneyBadger protocol that implements all the above sub(protocols) into a complete --production grade-- practical consensus engine.

Usage

Install dependencies

make deps

Run tests

make test
How to plug hbbft in to your existing setup

Create a new instance of HoneyBadger.

// Create a Config struct with your prefered settings.
cfg := hbbft.Config{
    // The number of nodes in the network.
    N: 4,
    // Identifier of this node.
    ID: 101,
    // Identifiers of the participating nodes.
    Nodes: uint64{67, 1, 99, 101},
    // The prefered batch size. If BatchSize is empty, an ideal batch size will
    // be choosen for you.
    BatchSize: 100,
}

// Create a new instance of the HoneyBadger engine and pass in the config.
hb := hbbft.NewHoneyBadger(cfg)

Filling the engine with transactions. Hbbft uses an interface to make it compatible with all types of transactions, the only contract a transaction have to fullfill is the Hash() []byte method.

// Transaction is an interface that abstract the underlying data of the actual
// transaction. This allows package hbbft to be easily adopted by other
// applications.
type Transaction interface {
  Hash() []byte
}

Adding new transactions can be done be calling the following method on the hb instance.
hb.AddTransaction(tx) // can be called in routines without any problem.

Starting the engine.

hb.Start() // will start proposing batches of transactions in the network.

Applications build on top of hbbft can decide when they access commited transactions. Once consumed the output will be reset.

hb.Outputs() // returns a map of commited transactions per epoch.

for epoch, tx := range hb.Outputs() {
  fmt.Printf("batch for epoch %d: %v\n", epoch, tx)
}

A working implementation can be found in the bench folder, where hbbft is implemented over local transport.

Current project state

  • Reliable Broadcast Algorithm
  • Binary Byzantine Agreement
  • Asynchronous Common Subset
  • HoneyBadger top level protocol

TODO

  • Threshold encryption
  • Configurable serialization for transactions

References

Other language implementations

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ACS

type ACS struct {
	// Config holds the ACS configuration.
	Config
	// contains filtered or unexported fields
}

ACS implements the Asynchronous Common Subset protocol. ACS assumes a network of N nodes that send signed messages to each other. There can be f faulty nodes where (3 * f < N). Each participating node proposes an element for inlcusion. The protocol guarantees that all of the good nodes output the same set, consisting of at least (N -f) of the proposed values.

Algorithm: ACS creates a Broadcast algorithm for each of the participating nodes. At least (N -f) of these will eventually output the element proposed by that node. ACS will also create and BBA instance for each participating node, to decide whether that node's proposed element should be inlcuded in common set. Whenever an element is received via broadcast, we imput "true" into the corresponding BBA instance. When (N-f) BBA instances have decided true we input false into the remaining ones, where we haven't provided input yet. Once all BBA instances have decided, ACS returns the set of all proposed values for which the decision was truthy.

func NewACS

func NewACS(cfg Config) *ACS

NewACS returns a new ACS instance configured with the given Config and node ids.

func (*ACS) Done

func (a *ACS) Done() bool

Done returns true whether ACS has completed its agreements and cleared its messageQue.

func (*ACS) HandleMessage

func (a *ACS) HandleMessage(senderID uint64, msg *ACSMessage) error

HandleMessage handles incoming messages to ACS and redirects them to the appropriate sub(protocol) instance.

func (*ACS) InputValue

func (a *ACS) InputValue(val []byte) error

InputValue sets the input value for broadcast and returns an initial set of Broadcast and ACS Messages to be broadcasted in the network.

func (*ACS) Output

func (a *ACS) Output() map[uint64][]byte

Output will return the output of the ACS instance. If the output was not nil then it will return the output else nil. Note that after consuming the output its will be set to nil forever.

type ACSMessage

type ACSMessage struct {
	// Unique identifier of the "proposing" node.
	ProposerID uint64
	// Actual payload beeing sent.
	Payload interface{}
}

ACSMessage represents a message sent between nodes in the ACS protocol.

type AgreementMessage

type AgreementMessage struct {
	// Epoch when this message was sent.
	Epoch int
	// The actual contents of the message.
	Message interface{}
}

AgreementMessage holds the epoch and the message sent in the BBA protocol.

func NewAgreementMessage

func NewAgreementMessage(e int, msg interface{}) *AgreementMessage

NewAgreementMessage constructs a new AgreementMessage.

type AuxRequest

type AuxRequest struct {
	Value bool
}

AuxRequest holds the output value.

type BBA

type BBA struct {
	// Config holds the BBA configuration.
	Config
	// contains filtered or unexported fields
}

BBA is the Binary Byzantine Agreement build from a common coin protocol.

func NewBBA

func NewBBA(cfg Config) *BBA

NewBBA returns a new instance of the Binary Byzantine Agreement.

func (*BBA) AcceptInput

func (b *BBA) AcceptInput() bool

AcceptInput returns true whether this bba instance is elligable for accepting a new input value.

func (*BBA) HandleMessage

func (b *BBA) HandleMessage(senderID uint64, msg *AgreementMessage) error

HandleMessage will process the given rpc message. The caller is resposible to make sure only RPC messages are passed that are elligible for the BBA protocol.

func (*BBA) InputValue

func (b *BBA) InputValue(val bool) error

InputValue will set the given val as the initial value to be proposed in the Agreement and returns an initial AgreementMessage or an error.

func (*BBA) Messages

func (b *BBA) Messages() []*AgreementMessage

Messages returns the que of messages. The message que get's filled after processing a protocol message. After calling this method the que will be empty. Hence calling Messages can only occur once in a single roundtrip.

func (*BBA) Output

func (b *BBA) Output() interface{}

Output will return the output of the bba instance. If the output was not nil then it will return the output else nil. Note that after consuming the output its will be set to nil forever.

type BroadcastMessage

type BroadcastMessage struct {
	Payload interface{}
}

BroadcastMessage holds the payload sent between nodes in the rbc protocol. Its basically just a wrapper to let top-level protocols distinguish incoming messages.

type BvalRequest

type BvalRequest struct {
	Value bool
}

BvalRequest holds the input value of the binary input.

type Config

type Config struct {
	// Number of participating nodes.
	N int
	// Number of faulty nodes.
	F int
	// Unique identifier of the node.
	ID uint64
	// Identifiers of the participating nodes.
	Nodes []uint64
	// Maximum number of transactions that will be comitted in one epoch.
	BatchSize int
}

Config holds the configuration of the top level HoneyBadger protocol as for its sub-protocols.

type EchoRequest

type EchoRequest struct {
	ProofRequest
}

EchoRequest represents the echoed version of the proof.

type HBMessage

type HBMessage struct {
	Epoch   uint64
	Payload interface{}
}

HBMessage is the top level message. It holds the epoch where the message was created and the actual payload.

type HoneyBadger

type HoneyBadger struct {
	// Config holds the configuration of the engine. This may not change
	// after engine initialization.
	Config
	// contains filtered or unexported fields
}

HoneyBadger represents the top-level protocol of the hbbft consensus.

func NewHoneyBadger

func NewHoneyBadger(cfg Config) *HoneyBadger

NewHoneyBadger returns a new HoneyBadger instance.

func (*HoneyBadger) AddTransaction

func (hb *HoneyBadger) AddTransaction(tx Transaction)

AddTransaction adds the given transaction to the internal buffer.

func (*HoneyBadger) HandleMessage

func (hb *HoneyBadger) HandleMessage(sid, epoch uint64, msg *ACSMessage) error

HandleMessage will process the given ACSMessage for the given epoch.

func (*HoneyBadger) LenMempool

func (hb *HoneyBadger) LenMempool() int

LenMempool returns the number of transactions in the buffer.

func (*HoneyBadger) Messages

func (hb *HoneyBadger) Messages() []MessageTuple

Messages returns all the internal messages from the message que. Note that the que will be empty after invoking this method.

func (*HoneyBadger) Outputs

func (hb *HoneyBadger) Outputs() map[uint64][]Transaction

Outputs returns the commited transactions per epoch.

func (*HoneyBadger) Start

func (hb *HoneyBadger) Start() error

Start attempt to start the consensus engine. TODO(@anthdm): Reconsider API change.

type LocalTransport

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

LocalTransport implements a local Transport. This is used to test hbbft without going over the network.

func NewLocalTransport

func NewLocalTransport(addr uint64) *LocalTransport

NewLocalTransport returns a new LocalTransport.

func (*LocalTransport) Addr

func (t *LocalTransport) Addr() uint64

Addr implements the Transport interface.

func (*LocalTransport) Broadcast

func (t *LocalTransport) Broadcast(id uint64, msg interface{}) error

Broadcast implements the Transport interface.

func (*LocalTransport) Connect

func (t *LocalTransport) Connect(addr uint64, tr Transport)

Connect implements the Transport interface.

func (*LocalTransport) Consume

func (t *LocalTransport) Consume() <-chan RPC

Consume implements the Transport interface.

func (*LocalTransport) SendMessage

func (t *LocalTransport) SendMessage(from, to uint64, msg interface{}) error

SendMessage implements the transport interface.

func (*LocalTransport) SendProofMessages

func (t *LocalTransport) SendProofMessages(id uint64, msgs []interface{}) error

SendProofMessages implements the Transport interface.

type MessageTuple

type MessageTuple struct {
	To      uint64
	Payload interface{}
}

MessageTuple holds the payload of the message along with the identifier of the receiver node.

type ProofRequest

type ProofRequest struct {
	RootHash []byte
	// Proof[0] will containt the actual data.
	Proof         [][]byte
	Index, Leaves int
}

ProofRequest holds the RootHash along with the Shard of the erasure encoded payload.

type RBC

type RBC struct {
	// Config holds the configuration.
	Config
	// contains filtered or unexported fields
}

RBC represents the instance of the "Reliable Broadcast Algorithm".

func NewRBC

func NewRBC(cfg Config, proposerID uint64) *RBC

NewRBC returns a new instance of the ReliableBroadcast configured with the given config

func (*RBC) HandleMessage

func (r *RBC) HandleMessage(senderID uint64, msg *BroadcastMessage) error

HandleMessage will process the given rpc message and will return a possible outcome. The caller is resposible to make sure only RPC messages are passed that are elligible for the RBC protocol.

func (*RBC) InputValue

func (r *RBC) InputValue(data []byte) ([]*BroadcastMessage, error)

InputValue will set the given data as value V. The data will first splitted into shards and additional parity shards (used for reconstruction), the equally splitted shards will be fed into a reedsolomon encoder. After encoding, only the requests for the other participants are beeing returned.

func (*RBC) Messages

func (r *RBC) Messages() []*BroadcastMessage

Messages returns the que of messages. The message que get's filled after processing a protocol message. After calling this method the que will be empty. Hence calling Messages can only occur once in a single roundtrip.

func (*RBC) Output

func (r *RBC) Output() []byte

Output will return the output of the rbc instance. If the output was not nil then it will return the output else nil. Note that after consuming the output its will be set to nil forever.

type RPC

type RPC struct {
	// NodeID is the unique identifier of the sending node.
	// TODO: consider renaming this to SenderID.
	NodeID uint64
	// Payload beeing send.
	Payload interface{}
}

RPC holds the payload send between participants in the consensus.

type ReadyRequest

type ReadyRequest struct {
	RootHash []byte
}

ReadyRequest holds the RootHash of the received proof and should be sent after receiving and validating enough proof chunks.

type Transaction

type Transaction interface {
	Hash() []byte
}

Transaction is an interface that abstract the underlying data of the actual transaction. This allows package hbbft to be easily adopted by other applications.

type Transport

type Transport interface {
	// Consume returns a channel used for consuming and responding to RPC
	// requests.
	Consume() <-chan RPC

	// SendProofMessages will equally spread the given messages under the
	// participating nodes.
	SendProofMessages(from uint64, msgs []interface{}) error

	// Broadcast multicasts the given messages to all connected nodes.
	Broadcast(from uint64, msg interface{}) error

	SendMessage(from, to uint64, msg interface{}) error

	// Connect is used to connect this tranport to another transport.
	Connect(uint64, Transport)

	// Addr returns the address of the transport. We address transport by the
	// id of the node.
	Addr() uint64
}

Transport is an interface that allows the abstraction of network transports.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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