gpbft

package
v0.0.0-...-c49d79d Latest Latest
Warning

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

Go to latest
Published: May 31, 2024 License: Apache-2.0, MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const CHAIN_MAX_LEN = 100

Maximum length of a chain value.

View Source
const DOMAIN_SEPARATION_TAG = "GPBFT"
View Source
const DOMAIN_SEPARATION_TAG_VRF = "VRF"

Variables

View Source
var (
	ErrValidationTooOld      = errors.New("message is for prior instance")
	ErrValidationNoCommittee = errors.New("no committee for instance")
	ErrValidationInvalid     = errors.New("message invalid")
	ErrValidationWrongBase   = errors.New("unexpected base chain")

	ErrReceivedWrongInstance    = errors.New("received message for wrong instance")
	ErrReceivedAfterTermination = errors.New("received message after terminating")
	ErrReceivedInternalError    = errors.New("error processing message")
)

Sentinel errors for the message validation and reception APIs.

Functions

func IsStrongQuorum

func IsStrongQuorum(part, total *StoragePower) bool

Check whether a portion of storage power is a strong quorum of the total

func MakeCid

func MakeCid(data []byte) []byte

Hashes the given data and returns a CBOR + blake2b-256 CID.

func ValidateMessage

func ValidateMessage(powerTable *PowerTable, beacon []byte, host Host, msg *GMessage) error

Checks message validity, including justification and signatures. An invalid message can never become valid, so may be dropped. This is a pure function and does not modify its arguments. It must be safe for concurrent use.

func VerifyTicket

func VerifyTicket(nn NetworkName, beacon []byte, instance uint64, round uint64, source PubKey, host VRFHost, ticket Ticket) bool

Types

type ActorID

type ActorID uint64

type CID

type CID = []byte

type Chain

type Chain interface {
	// Returns the supplemental data and the chain to propose for a new GPBFT instance.
	// The chain must be a suffix of the chain finalised by the immediately prior instance.
	// The supplemental data must be derived entirely from prior instances and all participants
	// must propose the same supplemental data.
	//
	// Returns an error if the chain for the instance is not available.
	GetProposalForInstance(instance uint64) (data *SupplementalData, chain ECChain, err error)

	// Returns the power table and beacon value to be used for a GPBFT instance.
	// These values should be derived from a chain previously received as final by the host,
	// or known to be final via some other channel (e.g. when bootstrapping the protocol).
	// The offset (how many instances to look back) is determined by the host.
	// Returns an error if the committee for the instance is not available.
	GetCommitteeForInstance(instance uint64) (power *PowerTable, beacon []byte, err error)
}

type ChainKey

type ChainKey string

A map key for a chain. The zero value means "bottom".

type Clock

type Clock interface {
	// Returns the current network time.
	Time() time.Time
	// Sets an alarm to fire after the given timestamp.
	// At most one alarm can be set at a time.
	// Setting an alarm replaces any previous alarm that has not yet fired.
	// The timestamp may be in the past, in which case the alarm will fire as soon as possible
	// (but not synchronously).
	SetAlarm(at time.Time)
}

type ConvergeTicket

type ConvergeTicket struct {
	Sender ActorID
	Ticket Ticket
}

type ConvergeValue

type ConvergeValue struct {
	Chain         ECChain
	Justification *Justification
}

type DecisionReceiver

type DecisionReceiver interface {
	// Receives a finality decision from the instance, with signatures from a strong quorum
	// of participants justifying it.
	// The decision payload always has round = 0 and step = DECIDE.
	// The notification must return the timestamp at which the next instance should begin,
	// based on the decision received (which may be in the past).
	// E.g. this might be: finalised tipset timestamp + epoch duration + stabilisation delay.
	ReceiveDecision(decision *Justification) time.Time
}

type ECChain

type ECChain []TipSet

A chain of tipsets comprising a base (the last finalised tipset from which the chain extends). and (possibly empty) suffix. Tipsets are assumed to be built contiguously on each other, though epochs may be missing due to null rounds. The zero value is not a valid chain, and represents a "bottom" value when used in a Granite message.

func NewChain

func NewChain(base TipSet, suffix ...TipSet) (ECChain, error)

Creates a new chain.

func (ECChain) Base

func (c ECChain) Base() *TipSet

Returns the base tipset.

func (ECChain) BaseChain

func (c ECChain) BaseChain() ECChain

Returns a new chain with the same base and no suffix. Invalid for a zero value.

func (ECChain) Eq

func (c ECChain) Eq(other ECChain) bool

Compares two ECChains for equality.

func (ECChain) Extend

func (c ECChain) Extend(tips ...TipSetKey) ECChain

func (ECChain) HasBase

func (c ECChain) HasBase(t *TipSet) bool

Check whether a chain has a specific base tipset. Always false for a zero value.

func (ECChain) HasPrefix

func (c ECChain) HasPrefix(other ECChain) bool

Checks whether a chain has some prefix (including the base). Always false for a zero value.

func (ECChain) HasTipset

func (c ECChain) HasTipset(t *TipSet) bool

Checks whether a chain has some tipset (including as its base).

func (ECChain) Head

func (c ECChain) Head() *TipSet

Returns the last tipset in the chain. This could be the base tipset if there is no suffix. This will panic on a zero value.

func (ECChain) IsZero

func (c ECChain) IsZero() bool

func (ECChain) Key

func (c ECChain) Key() ChainKey

Returns an identifier for the chain suitable for use as a map key. This must completely determine the sequence of tipsets in the chain.

func (ECChain) Prefix

func (c ECChain) Prefix(to int) ECChain

Returns a chain with suffix (after the base) truncated to a maximum length. Prefix(0) returns the base chain. Invalid for a zero value.

func (ECChain) SameBase

func (c ECChain) SameBase(other ECChain) bool

Checks whether two chains have the same base. Always false for a zero value.

func (ECChain) String

func (c ECChain) String() string

func (ECChain) Suffix

func (c ECChain) Suffix() []TipSet

Returns the suffix of the chain after the base. An empty slice for a zero value.

func (ECChain) Validate

func (c ECChain) Validate() error

Validates a chain value, returning an error if it finds any issues. A chain is valid if it meets the following criteria: 1) All contained tipsets are non-empty. 2) All epochs are >= 0 and increasing. 3) The chain is not longer than CHAIN_MAX_LEN. An entirely zero-valued chain itself is deemed valid. See ECChain.IsZero.

type GMessage

type GMessage struct {
	// ID of the sender/signer of this message (a miner actor ID).
	Sender ActorID
	// Vote is the payload that is signed by the signature
	Vote Payload
	// Signature by the sender's public key over Instance || Round || Step || Value.
	Signature []byte
	// VRF ticket for CONVERGE messages (otherwise empty byte array).
	Ticket Ticket
	// Justification for this message (some messages must be justified by a strong quorum of messages from some previous step).
	Justification *Justification
}

A message in the Granite protocol. The same message structure is used for all rounds and phases. Note that the message is self-attesting so no separate envelope or signature is needed. - The signature field fixes the included sender ID via the implied public key; - The signature payload includes all fields a sender can freely choose; - The ticket field is a signature of the same public key, so also self-attesting.

func (*GMessage) MarshalCBOR

func (t *GMessage) MarshalCBOR(w io.Writer) error

func (GMessage) String

func (m GMessage) String() string

func (*GMessage) UnmarshalCBOR

func (t *GMessage) UnmarshalCBOR(r io.Reader) (err error)

type Host

type Host interface {
	Chain
	Network
	Clock
	Signatures
	DecisionReceiver
}

Participant interface to the host system resources.

type Justification

type Justification struct {
	// Vote is the payload that is signed by the signature
	Vote Payload
	// Indexes in the base power table of the signers (bitset)
	Signers bitfield.BitField
	// BLS aggregate signature of signers
	Signature []byte
}

func (*Justification) MarshalCBOR

func (t *Justification) MarshalCBOR(w io.Writer) error

func (*Justification) UnmarshalCBOR

func (t *Justification) UnmarshalCBOR(r io.Reader) (err error)

type MessageBuilder

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

func NewMessageBuilder

func NewMessageBuilder(powerTable powerTableAccessor) MessageBuilder

NewMessageBuilder creates a new message builder with the provided beacon for ticket, justification and payload.

func NewMessageBuilderWithPowerTable

func NewMessageBuilderWithPowerTable(power *PowerTable) MessageBuilder

NewMessageBuilderWithPowerTable allows to create a new message builder from an existing power table.

This is needed to sign forged messages in adversary hosts

func (MessageBuilder) BeaconForTicket

func (mb MessageBuilder) BeaconForTicket() []byte

func (MessageBuilder) Build

func (mt MessageBuilder) Build(networkName NetworkName, signer SignerWithMarshaler, id ActorID) (*GMessage, error)

Build uses the builder and a signer interface to build GMessage It is a shortcut for when separated flow is not required

func (MessageBuilder) Justification

func (mb MessageBuilder) Justification() *Justification

func (MessageBuilder) Payload

func (mb MessageBuilder) Payload() Payload

func (MessageBuilder) PrepareSigningInputs

func (mt MessageBuilder) PrepareSigningInputs(msh SigningMarshaler, networkName NetworkName, id ActorID) (SignatureBuilder, error)

func (*MessageBuilder) SetBeaconForTicket

func (mb *MessageBuilder) SetBeaconForTicket(b []byte)

SetBeaconForTicket sets the beacon for the ticket in the message builder.

func (*MessageBuilder) SetJustification

func (mb *MessageBuilder) SetJustification(j *Justification)

SetJustification sets the justification in the message builder.

func (*MessageBuilder) SetPayload

func (mb *MessageBuilder) SetPayload(p Payload)

SetPayload sets the payload in the message builder.

type MessageReceiver

type MessageReceiver interface {
	// Receives a validated Granite message from some other participant.
	// Returns an error, wrapping (use errors.Is()/Unwrap()):
	// - ErrValidationTooOld if the message is for a prior instance
	// - ErrValidationWrongBase if the message has an invalid base chain
	// - ErrReceivedAfterTermination if the message is received after the instance has terminated (a programming error)
	// - both ErrReceivedInternalError and a cause if there was an internal error processing the message
	// This method is not safe for concurrent use.
	ReceiveMessage(msg ValidatedMessage) error
	// This method is not safe for concurrent use.
	ReceiveAlarm() error
}

Receives a Granite protocol message.

type MessageValidator

type MessageValidator interface {
	// Validates a Granite message.
	// An invalid message can never become valid, so may be dropped.
	// Returns an error, wrapping (use errors.Is()/Unwrap()):
	// - ErrValidationTooOld if the message is for a prior instance;
	// - both ErrValidationNoCommittee and an error describing the reason;
	//   if there is no committee available with with to validate the message;
	// - both ErrValidationInvalid and a cause if the message is invalid,
	// Returns a validated message if the message is valid.
	//
	// Implementations must be safe for concurrent use.
	ValidateMessage(msg *GMessage) (valid ValidatedMessage, err error)
}

type Network

type Network interface {
	// Returns the network's name (for signature separation)
	NetworkName() NetworkName
	// Requests that the message is signed and broadcasted, it should also be delivered locally
	RequestBroadcast(mb *MessageBuilder) error
}

Endpoint to which participants can send messages.

type NetworkName

type NetworkName string

NetworkName provides separation between different networks it is implicitly included in all signatures and VRFs

func (NetworkName) DatastorePrefix

func (nn NetworkName) DatastorePrefix() datastore.Key

func (NetworkName) PubSubTopic

func (nn NetworkName) PubSubTopic() string

type Option

type Option func(*options) error

Option represents a configurable parameter.

func WithDelta

func WithDelta(d time.Duration) Option

WithDelta sets the expected bound on message propagation latency. Defaults to 3 seconds if unspecified. Delta must be larger than zero.

The default of 3 seconds for the value of Dela is based previous observations of the upper bound on the GossipSub network-wide propagation time in Filecoin network.

See: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0086.md#synchronization-of-participants-in-the-current-instance

func WithDeltaBackOffExponent

func WithDeltaBackOffExponent(e float64) Option

WithDeltaBackOffExponent sets the delta back-off exponent for each round. Defaults to 1.3 if unspecified. It must be larger than zero.

See: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0086.md#synchronization-of-participants-in-the-current-instance

func WithInitialInstance

func WithInitialInstance(i uint64) Option

WithInitialInstance sets the first instance number. Defaults to zero if unspecified.

func WithMaxLookaheadRounds

func WithMaxLookaheadRounds(r uint64) Option

WithMaxLookaheadRounds sets the maximum number of rounds ahead of the current round for which messages without justification are buffered. Setting a max value of larger than zero would aid gPBFT to potentially reach consensus in fewer rounds during periods of asynchronous broadcast as well as re-broadcast. Defaults to zero if unset.

func WithTracer

func WithTracer(t Tracer) Option

WithTracer sets the Tracer for this gPBFT instance, which receives diagnostic logs about the state mutation. Defaults to no tracer if unspecified.

type PanicError

type PanicError struct {
	Err any
}

func (*PanicError) Error

func (e *PanicError) Error() string

type Participant

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

An F3 participant runs repeated instances of Granite to finalise longer chains.

func NewParticipant

func NewParticipant(host Host, o ...Option) (*Participant, error)

func (*Participant) CurrentRound

func (p *Participant) CurrentRound() uint64

func (*Participant) Describe

func (p *Participant) Describe() string

func (*Participant) ReceiveAlarm

func (p *Participant) ReceiveAlarm() (err error)

func (*Participant) ReceiveMessage

func (p *Participant) ReceiveMessage(vmsg ValidatedMessage) (err error)

Receives a validated Granite message from some other participant.

func (*Participant) Start

func (p *Participant) Start() (err error)

Fetches the preferred EC chain for the instance and begins the GPBFT protocol.

func (*Participant) ValidateMessage

func (p *Participant) ValidateMessage(msg *GMessage) (valid ValidatedMessage, err error)

Validates a message

type Payload

type Payload struct {
	// GossiPBFT instance (epoch) number.
	Instance uint64
	// GossiPBFT round number.
	Round uint64
	// GossiPBFT step name.
	Step Phase
	// The common data.
	SupplementalData SupplementalData
	// The value agreed-upon in a single instance.
	Value ECChain
}

Fields of the message that make up the signature payload.

func (*Payload) Eq

func (p *Payload) Eq(other *Payload) bool

func (*Payload) MarshalCBOR

func (t *Payload) MarshalCBOR(w io.Writer) error

func (*Payload) MarshalForSigning

func (p *Payload) MarshalForSigning(nn NetworkName) []byte

func (*Payload) UnmarshalCBOR

func (t *Payload) UnmarshalCBOR(r io.Reader) (err error)

type Phase

type Phase uint8
const (
	INITIAL_PHASE Phase = iota
	QUALITY_PHASE
	CONVERGE_PHASE
	PREPARE_PHASE
	COMMIT_PHASE
	DECIDE_PHASE
	TERMINATED_PHASE
)

func (Phase) String

func (p Phase) String() string

type PowerEntries

type PowerEntries []PowerEntry

func (PowerEntries) Len

func (p PowerEntries) Len() int

Len returns the number of entries in this PowerTable.

func (PowerEntries) Less

func (p PowerEntries) Less(i, j int) bool

Less determines if the entry at index i should be sorted before the entry at index j. Entries are sorted descending order of their power, where entries with equal power are sorted by ascending order of their ID. This ordering is guaranteed to be stable, since a valid PowerTable cannot contain entries with duplicate IDs; see Validate.

func (*PowerEntries) MarshalCBOR

func (t *PowerEntries) MarshalCBOR(w io.Writer) error

func (PowerEntries) Swap

func (p PowerEntries) Swap(i, j int)

Swap swaps the entry at index i with the entry at index j. This function must not be called directly since it is used as part of sort.Interface.

func (*PowerEntries) UnmarshalCBOR

func (t *PowerEntries) UnmarshalCBOR(r io.Reader) (err error)

type PowerEntry

type PowerEntry struct {
	ID     ActorID
	Power  *StoragePower
	PubKey PubKey
}

PowerEntry represents a single entry in the PowerTable, including ActorID and its StoragePower and PubKey.

func (*PowerEntry) MarshalCBOR

func (t *PowerEntry) MarshalCBOR(w io.Writer) error

func (*PowerEntry) UnmarshalCBOR

func (t *PowerEntry) UnmarshalCBOR(r io.Reader) (err error)

type PowerTable

type PowerTable struct {
	Entries PowerEntries    // Slice to maintain the order. Meant to be maintained in order in order by (Power descending, ID ascending)
	Lookup  map[ActorID]int // Maps ActorID to the index of the associated entry in Entries
	Total   *StoragePower
}

PowerTable maps ActorID to a unique index in the range [0, len(powerTable.Entries)). Entries is the reverse mapping to a PowerEntry.

func NewPowerTable

func NewPowerTable() *PowerTable

NewPowerTable creates a new PowerTable from a slice of PowerEntry . It is more efficient than Add, as it only needs to sort the entries once. Note that the function takes ownership of the slice - it must not be modified afterwards.

func (*PowerTable) Add

func (p *PowerTable) Add(entries ...PowerEntry) error

Add inserts one or more entries to this PowerTable.

Each inserted entry must meet the following criteria: * It must not already be present int the PowerTable. * It must have StoragePower larger than zero. * It must have a non-zero length public key.

func (*PowerTable) Copy

func (p *PowerTable) Copy() *PowerTable

Copy creates a deep copy of this PowerTable.

func (*PowerTable) Get

func (p *PowerTable) Get(id ActorID) (*StoragePower, PubKey)

Get retrieves the StoragePower and PubKey for the given id, if present in the table. Otherwise, returns nil.

func (*PowerTable) Has

func (p *PowerTable) Has(id ActorID) bool

Has check whether this PowerTable contains an entry for the given id.

func (*PowerTable) Len

func (p *PowerTable) Len() int

Len returns the number of entries in this PowerTable.

func (*PowerTable) Less

func (p *PowerTable) Less(i, j int) bool

Less determines if the entry at index i should be sorted before the entry at index j. Entries are sorted descending order of their power, where entries with equal power are sorted by ascending order of their ID. This ordering is guaranteed to be stable, since a valid PowerTable cannot contain entries with duplicate IDs; see Validate.

func (*PowerTable) Swap

func (p *PowerTable) Swap(i, j int)

Swap swaps the entry at index i with the entry at index j. This function must not be called directly since it is used as part of sort.Interface.

func (*PowerTable) Validate

func (p *PowerTable) Validate() error

Validate checks the validity of this PowerTable. Such table must meet the following criteria: * Its entries must be in order as defined by Less. * It must not contain any entries with duplicate ID. * All entries must have power larger than zero * All entries must have non-zero public key. * PowerTable.Total must correspond to the total aggregated power of entries. * PowerTable.Lookup must contain the expected mapping of entry actor ID to index.

type PubKey

type PubKey []byte

type QuorumResult

type QuorumResult struct {
	// Signers is an array of indexes into the powertable, sorted in increasing order
	Signers    []int
	PubKeys    []PubKey
	Signatures [][]byte
}

func (QuorumResult) Aggregate

func (q QuorumResult) Aggregate(v Verifier) ([]byte, error)

func (QuorumResult) SignersBitfield

func (q QuorumResult) SignersBitfield() bitfield.BitField

type Receiver

type Receiver interface {
	// Begins executing the protocol.
	// The node will request the canonical chain to propose from the host.
	Start() error
	MessageValidator
	MessageReceiver
}

Interface which network participants must implement.

type SignatureBuilder

type SignatureBuilder struct {
	NetworkName NetworkName
	// contains filtered or unexported fields
}

func (*SignatureBuilder) Justification

func (sb *SignatureBuilder) Justification() *Justification

func (*SignatureBuilder) ParticipantID

func (sb *SignatureBuilder) ParticipantID() ActorID

func (*SignatureBuilder) Payload

func (sb *SignatureBuilder) Payload() Payload

func (*SignatureBuilder) PayloadToSign

func (sb *SignatureBuilder) PayloadToSign() []byte

func (*SignatureBuilder) PubKey

func (sb *SignatureBuilder) PubKey() PubKey

func (*SignatureBuilder) VRFToSign

func (sb *SignatureBuilder) VRFToSign() []byte

type Signatures

type Signatures interface {
	SigningMarshaler
	Signer
	Verifier
}

type Signer

type Signer interface {
	// Signs a message with the secret key corresponding to a public key.
	Sign(sender PubKey, msg []byte) ([]byte, error)
}

type SignerWithMarshaler

type SignerWithMarshaler interface {
	Signer
	SigningMarshaler
}

type SigningMarshaler

type SigningMarshaler interface {
	// MarshalPayloadForSigning marshals the given payload into the bytes that should be signed.
	// This should usually call `Payload.MarshalForSigning(NetworkName)` except when testing as
	// that method is slow (computes a merkle tree that's necessary for testing).
	// Implementations must be safe for concurrent use.
	MarshalPayloadForSigning(NetworkName, *Payload) []byte
}

type StoragePower

type StoragePower = big.Int

func NewStoragePower

func NewStoragePower(value int64) *StoragePower

Creates a new StoragePower struct with a specific value and returns the result

type SupplementalData

type SupplementalData struct {
	// Merkle-tree of instance-specific commitments. Currently empty but this will eventually
	// include things like snark-friendly power-table commitments.
	Commitments [32]byte
	// The DagCBOR-blake2b256 CID of the power table used to validate the next instance, taking
	// lookback into account.
	PowerTable CID // []PowerEntry
}

func (*SupplementalData) Eq

func (d *SupplementalData) Eq(other *SupplementalData) bool

func (*SupplementalData) MarshalCBOR

func (t *SupplementalData) MarshalCBOR(w io.Writer) error

func (*SupplementalData) UnmarshalCBOR

func (t *SupplementalData) UnmarshalCBOR(r io.Reader) (err error)

type Ticket

type Ticket []byte

A ticket is a signature over some common payload.

func MakeTicket

func MakeTicket(nn NetworkName, beacon []byte, instance uint64, round uint64, source PubKey, host VRFHost) (Ticket, error)

type TipSet

type TipSet struct {
	// The EC epoch (strictly increasing).
	Epoch int64
	// The tipset's key (canonically ordered concatenated block-header CIDs).
	Key TipSetKey
	// Blake2b256-32 CID of the CBOR-encoded power table.
	PowerTable CID // []PowerEntry
	// Keccak256 root hash of the commitments merkle tree.
	Commitments [32]byte
}

TipSet represents a single EC tipset.

func (*TipSet) Equal

func (ts *TipSet) Equal(b *TipSet) bool

func (*TipSet) IsZero

func (ts *TipSet) IsZero() bool

func (*TipSet) MarshalCBOR

func (t *TipSet) MarshalCBOR(w io.Writer) error

func (*TipSet) MarshalForSigning

func (ts *TipSet) MarshalForSigning() []byte

func (*TipSet) String

func (ts *TipSet) String() string

func (*TipSet) UnmarshalCBOR

func (t *TipSet) UnmarshalCBOR(r io.Reader) (err error)

type TipSetKey

type TipSetKey = []byte

TipSetKey is the canonically ordered concatenation of the block CIDs in a tipset.

type Tracer

type Tracer interface {
	Log(format string, args ...any)
}

Tracer collects trace logs that capture logical state changes. The primary purpose of Tracer is to aid debugging and simulation.

type VRFHost

type VRFHost interface {
	Network
	Signer
	Verifier
}

type ValidatedMessage

type ValidatedMessage interface {
	// Returns the validated message.
	Message() *GMessage
}

Opaque type tagging a validated message.

type Verifier

type Verifier interface {
	// Verifies a signature for the given public key.
	// Implementations must be safe for concurrent use.
	Verify(pubKey PubKey, msg, sig []byte) error
	// Aggregates signatures from a participants.
	Aggregate(pubKeys []PubKey, sigs [][]byte) ([]byte, error)
	// VerifyAggregate verifies an aggregate signature.
	// Implementations must be safe for concurrent use.
	VerifyAggregate(payload, aggSig []byte, signers []PubKey) error
}

Jump to

Keyboard shortcuts

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