rrr

package
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Sep 2, 2022 License: LGPL-3.0 Imports: 18 Imported by: 1

Documentation

Index

Constants

View Source
const (
	RRRActiveMethodSortEndorsers = "sortendorsers"
	// RRRActiveMethodRotateCandidates is implemented as a variant on
	// sortendorsers where rather than idling leaders that fail to produce
	// within Nc, we 'rotate' the candidate selection through the active
	// selection acording to the number of failed rounds.
	RRRActiveMethodRotateCandidates = "rotatecandidates"
	RRRActiveMethodSampleAged       = "sampleaged"
)
View Source
const (
	AddressLength = 20
	HashLen       = 32
)

Variables

View Source
var (
	ErrIntentAndConfirmPhaseToLarge = errors.New("intent + confirm phase can not be longer than the round")
	ErrIncompatibleChainReader      = errors.New("chainreader missing required interfaces for RRR")
	ErrNoGenesisHeader              = errors.New("failed to get genesis header")
	ErrNotLeaderCandidate           = errors.New("expected to be leader candidate")
	ErrEngineStopped                = errors.New("consensus not running")
	ErrRMsgInvalidCode              = errors.New("recevived RMsg with invalid code")
)
View Source
var (
	ErrUnknownAncestor      = errors.New("unknown ancestor")
	ErrDecodingGenesisExtra = errors.New("failed to decode extra field from genesis block")
	ErrBadHeaderSeal        = errors.New("invalid or corrupt header seal")
)
View Source
var DefaultConfig = &Config{
	IntentPhase:       1000,
	ConfirmPhase:      1000,
	RoundLength:       4000,
	Candidates:        2,
	Endorsers:         7,
	Quorum:            4,
	Activity:          2000,
	StablePrefixDepth: 6,
	MinIdleAttempts:   5,
	GossipFanout:      4,
	ActivityMethod:    RRRActiveMethodSortEndorsers,
}

DefaultConfig provides the default rrr consensus configuration

View Source
var (
	ErrBranchDetected = errors.New("branch detected")
)
View Source
var (
	ErrFutureBlock = errors.New("the time on the head block is in the future with respect to the reference value")
)
View Source
var (
	ErrGenesisExtraDigestMismatch = errors.New("the included digest of the genesis extra doesn't match the actual")
)
View Source
var (
	ErrSignedDecodeSignedFailed = errors.New("decoding signed rlp struct failed")
)

Functions

func BytesToPublic

func BytesToPublic(c CipherSuite, b []byte) (*ecdsa.PublicKey, error)

func ConditionSeed

func ConditionSeed(seed []byte) (uint64, error)

ConditionSeed takes a 32 byte input and XOR's it into a single uint64

func NodeIDBytesFromPub

func NodeIDBytesFromPub(c CipherSuite, pub *ecdsa.PublicKey) []byte

NodeIDBytesFromPub NodeID is Keccak256 (Pub.X || Pub.Y ) In contexts where we have the id and a signature, we can recover the pub key of the signer using Ecrecover

func PubMarshal

func PubMarshal(c CipherSuite, pub *ecdsa.PublicKey) []byte

PubMarshal converts public ecdsa key into the uncompressed form specified in section 4.3.6 of ANSI X9.62

func RandSampleRange

func RandSampleRange(source DRNG, limit int, s []int) []int

func RandSelect

func RandSelect(source DRNG, limit, nsamples int) map[int]bool

func ReadBits

func ReadBits(bigint *big.Int, buf []byte)

func RecoverPublic

func RecoverPublic(c CipherSuite, h []byte, sig []byte) (*ecdsa.PublicKey, error)

RecoverPublic ...

func RoundsInRange

func RoundsInRange(start time.Time, end time.Time, roundLength uint64) uint64

func RoundsSince

func RoundsSince(when time.Time, roundLength uint64) uint64

RoundsSince returns the number of rounds since the provided time for the given round length in seconds.

func VerifyNodeSig

func VerifyNodeSig(c CipherSuite, nodeID Hash, digest, sig []byte) bool

VerifyNodeSig verifies if sig over digest was produced using the private key corresponding to nodeID. We EC recover the public key from the digest and the signature and then compare the hash of the recovered public key with the node ID. As ethereum node identities are the hash of the node's public key, this is equivelant to verification using the public key.

https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery:

"The recovery algorithm can only be used to check validity of a signature if
the signer's public key (or its hash) is known beforehand"

Note: Use VerifyRecoverNodeSig if you want the err from Ecrecover rather than true/false

func VerifyRecoverNodeSig

func VerifyRecoverNodeSig(c CipherSuite, nodeID Hash, digest, sig []byte) (bool, []byte, error)

Types

type ActiveSelection

type ActiveSelection interface {

	// AccumulateActive should be called each time a new block arrives to
	// maintain the active selection of candidates and endorsers.
	AccumulateActive(
		roundNumber uint64, chainID Hash, chain BlockHeaderReader, head BlockHeader,
	) error
	NumActive() int

	NOldest(roundNumber uint64, n int) []Address

	NextActiveSample(roundNumber uint64, source DRNG, s []int) []int

	// SelectCandidatesAndEndorsers should be called once a round with a fresh
	// permutation of indices into the active selection. There must be exactly
	// nEndorsers worth of indices.
	SelectCandidatesAndEndorsers(
		roundNumber uint64, permutation []int,
	) (map[Address]bool, map[Address]bool, error)

	// Reset resets and primes the active selection such that head - ta is the
	// furthest back the next selection will look
	Reset(head BlockHeader)

	// Prime primes the active selection such that the next selection will look as
	// far back as head - ta but no further
	Prime(head BlockHeader)

	// AgeOf returns the age of the identity. The boolean return is false if the
	// identity is not active.
	AgeOf(nodeID Address) (uint64, bool)

	IsActive(roundNumber uint64, addr Address) bool
}

func NewActiveSelection

func NewActiveSelection(
	config *Config, codec *CipherCodec, selfNodeID Hash, logger Logger) ActiveSelection

func NewActiveSelection3

func NewActiveSelection3(
	config *Config, codec *CipherCodec, selfNodeID Hash, logger Logger) ActiveSelection

type Address

type Address [20]byte

Address is the ethereum style right most 20 bytes of Keccak256 (pub.X || pub.Y )

func PubToAddress

func PubToAddress(c CipherSuite, pub *ecdsa.PublicKey) Address

func (Address) Hex

func (a Address) Hex() string

Hex gets the hex string for the Address

func (Address) HexShort

func (a Address) HexShort() string

HexShort returns an abbreviated hex address

type Alpha

type Alpha struct {
	Contribution Hash
	Sig          [65]byte
}

Alpha encodes the seed contribution for a single genesis identity. The initial seed is calculted using the keccak of the catentaion of each contribution::

alpha = KeccaK(contribution-id0 | ... | contribution-idN)
seed, pi =  VRF-Prove(alpha).

The original paper suggests a warmup phase in the consensus protocol which utilises RandHound and this is planed for future work.

type BlockActivity

type BlockActivity struct {
	Confirm     []Endorsement
	Enrol       []Enrolment
	SealerID    Hash
	SealerPub   []byte
	RoundNumber uint64
}

BlockActivity is the decoded RRR consensus block activity data from the block header extra data.

type BlockHeader

type BlockHeader interface {
	Hash() [32]byte        // includes rrr seal
	HashForSeal() [32]byte // excludes rrr seal
	GetParentHash() [32]byte
	GetRoot() [32]byte
	GetTxHash() [32]byte
	GetNumber() *big.Int
	GetTime() uint64
	GetSeal() []byte
	GetRound(SignedExtraDecoder) (uint64, error)
	GetNonce() [8]byte
	GetExtra() []byte
}

type BlockHeaderReader

type BlockHeaderReader interface {
	GetHeaderByHash(hash [32]byte) BlockHeader
}

BlockHeaderReader defines the interface required by AccumulateActive

type Broadcaster

type Broadcaster interface {
	PeerFinder
	// Broadcast self, peers, msg
	Broadcast(Address, map[Address]Peer, []byte) error

	// SendSignedEndorsement ...
	SendSignedEndorsement(intenderAddr Address, et *EngSignedIntent) error
}

The engine supplies these so that the roundstate can call out to the network at the right points.

type ByAge

type ByAge []selectionItem

func (ByAge) Len

func (a ByAge) Len() int

func (ByAge) Less

func (a ByAge) Less(i, j int) bool

func (ByAge) Swap

func (a ByAge) Swap(i, j int)

type BytesCodec

type BytesCodec interface {
	BytesEncoder
	BytesDecoder
}

type BytesDecoder

type BytesDecoder interface {
	DecodeBytes(b []byte, val interface{}) error
}

type BytesEncoder

type BytesEncoder interface {
	EncodeToBytes(val interface{}) ([]byte, error)
}

type ChainInit

type ChainInit struct {
	ExtraHeader
	Alpha []Alpha // one per enrolment, contributions are catenated in ident genesis age order
}

ChainInit holds the RRR consensus genesis configuration, including genesis enroled identities

type CipherCodec

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

func NewCodec

func NewCodec(c CipherSuite, ed BytesCodec) *CipherCodec

func (*CipherCodec) BytesToPublic

func (codec *CipherCodec) BytesToPublic(pub []byte) (*ecdsa.PublicKey, error)

func (*CipherCodec) ChainID

func (codec *CipherCodec) ChainID(ci *ChainInit) (Hash, error)

ChainID returns the ChainID

func (*CipherCodec) DecodeBlockActivity

func (codec *CipherCodec) DecodeBlockActivity(a *BlockActivity, chainID Hash, header BlockHeader) error

Decode decodes the RRR consensus activity data from the header extra data. Any activity previously held is completely discarded

func (*CipherCodec) DecodeBytes

func (codec *CipherCodec) DecodeBytes(b []byte, val interface{}) error

func (*CipherCodec) DecodeGenesisExtra

func (codec *CipherCodec) DecodeGenesisExtra(genesisExtra []byte, extra *GenesisExtraData) error

DecodeGenesisExtra decodes the RRR genesis extra data

func (*CipherCodec) DecodeHeaderSeal

func (codec *CipherCodec) DecodeHeaderSeal(header BlockHeader) (*SignedExtraData, Hash, []byte, error)

func (*CipherCodec) DecodeSigned

func (codec *CipherCodec) DecodeSigned(msg []byte) ([65]byte, []byte, []byte, error)

decodeSigned decodes a hash and its 65 byte ecdsa signture and recovers the puplic key. In this implementation, the recovered public key is the RRR long term identity and we pretty much always want that to hand.

func (*CipherCodec) DecodeSignedEndorsement

func (codec *CipherCodec) DecodeSignedEndorsement(e *SignedEndorsement, b []byte) ([]byte, error)

DecodeSigned decodes the endorsment and returns the signers ecrecovered public key

func (*CipherCodec) DecodeSignedExtraData

func (codec *CipherCodec) DecodeSignedExtraData(e *SignedExtraData, b []byte) ([]byte, error)

DecodeSigned decodes a SignedExtraData from the stream

func (*CipherCodec) DecodeSignedIntent

func (codec *CipherCodec) DecodeSignedIntent(i *SignedIntent, b []byte) ([]byte, error)

DecodeSigned decodes ... (does not verify)

func (*CipherCodec) EncodeHashGenesisExtraData

func (codec *CipherCodec) EncodeHashGenesisExtraData(gd *GenesisExtraData) ([]byte, error)

EncodeHashGenesisExtraData encodes

func (*CipherCodec) EncodeSignEndorsement

func (codec *CipherCodec) EncodeSignEndorsement(e *SignedEndorsement, k *ecdsa.PrivateKey) ([]byte, error)

EncodeSignEndorsement encode and sign an endorsment

func (*CipherCodec) EncodeSignExtraData

func (codec *CipherCodec) EncodeSignExtraData(e *SignedExtraData, k *ecdsa.PrivateKey) ([]byte, error)

SignedEncode signs and encodes the extra data

func (*CipherCodec) EncodeSignIntent

func (codec *CipherCodec) EncodeSignIntent(i *SignedIntent, k *ecdsa.PrivateKey) ([]byte, error)

EncodeSignIntent encodes the intent body, signs the result and returns the serialised encoding of the result. k will typically be a leader candidate private key.

func (*CipherCodec) EncodeToBytes

func (codec *CipherCodec) EncodeToBytes(val interface{}) ([]byte, error)

func (*CipherCodec) FillEnrolmentQuote

func (codec *CipherCodec) FillEnrolmentQuote(q []byte, u Hash, a *ecdsa.PrivateKey) error

FillEnrolmentQuote intitialises a Quote for an identity to be enroled on the chain. a is the attestor. For genesis enrolment, this should be the chain creators private key. u is the 'userdata' hash to attest. For genesis identity enrolment it is just the enode identity directly (they are already 32 byte hashes). For operational enrolment it the hash of the rlp encoded EnrolmentBinding struct

func (*CipherCodec) HashEnrolmentBinding

func (codec *CipherCodec) HashEnrolmentBinding(e *EnrolmentBinding) (Hash, error)

U encodes the userdata hash to sign for the enrolment.

func (*CipherCodec) HashIntent

func (codec *CipherCodec) HashIntent(i *Intent) (Hash, error)

Hash hashes the intent

func (*CipherCodec) Keccak256Hash

func (codec *CipherCodec) Keccak256Hash(b ...[]byte) Hash

func (*CipherCodec) NodeIDBytesFromPub

func (codec *CipherCodec) NodeIDBytesFromPub(pub *ecdsa.PublicKey) []byte

func (*CipherCodec) NodeIDFromPub

func (codec *CipherCodec) NodeIDFromPub(pub *ecdsa.PublicKey) Hash

func (*CipherCodec) NodeIDFromPubBytes

func (codec *CipherCodec) NodeIDFromPubBytes(pub []byte) (Hash, error)

func (*CipherCodec) PopulateChainInit

func (codec *CipherCodec) PopulateChainInit(
	ci *ChainInit, ck *ecdsa.PrivateKey, initIdents []Enrolment, alphaContrib map[Hash]Alpha) error

Populate fills in a ChainInit ready for encoding in the genesis extraData See EIP-rrr/extraData of Block0/9.

func (*CipherCodec) RecoverEnrolerID

func (codec *CipherCodec) RecoverEnrolerID(q Quote, u Hash) (Hash, error)

RecoverEnrolerID recovers the identity that signed the enrolment hash u.

func (*CipherCodec) RecoverEnrolmentPublic

func (codec *CipherCodec) RecoverEnrolmentPublic(q Quote, u Hash) (*ecdsa.PublicKey, error)

RecoverEnrolmentPublic recovers the public component of the key which signed the enrolment from the signature q and and the userdata hash u. For a genesis enrolment, that is just the nodeid directly. For operational enrolments, obtain u by filling in the EnrolementBinding type and calling HashEnrolmentBinding()

func (*CipherCodec) SignEnrolmentBindingHash

func (codec *CipherCodec) SignEnrolmentBindingHash(
	q *Quote, key *ecdsa.PrivateKey, chainID Hash, nodeid Hash, round uint64,
	blockHash Hash, reEnrol bool,
) error

SignIdentityEnrolment fills in a quote for operational enrolment of the supplied nodeid. This binds the enrolment to the chain identified by chainID. Round is the current round of consensus. blockHash identifies the current head of the chain (selected branch)

func (*CipherCodec) SignedEncode

func (codec *CipherCodec) SignedEncode(k *ecdsa.PrivateKey, v interface{}) ([65]byte, []byte, error)

func (*CipherCodec) VerifyNodeSig

func (codec *CipherCodec) VerifyNodeSig(
	nodeID Hash, digest, sig []byte) bool

VerifyNodeSig verifies that sig over digest was produced by the public key for the node identified by nodeID. This works because the nodeID is the hash of the nodes public key.

func (*CipherCodec) VerifyRecoverNodeSig

func (codec *CipherCodec) VerifyRecoverNodeSig(
	nodeID Hash, digest, sig []byte) (bool, []byte, error)

VerifyRecoverNodeSig verifies that sig over digest was produced by the public key for the node identified by nodeID and returns the recovered public key bytes. This works because the nodeID is the hash of the nodes public key.

type CipherSuite

type CipherSuite interface {
	Curve() elliptic.Curve

	// Keccak256 returns a digest suitable for Sign. (draft sha3 before the padding was added)
	Keccak256(b ...[]byte) []byte

	// Sign is given a digest to sign.
	Sign(digest []byte, key *ecdsa.PrivateKey) ([]byte, error)

	// VerifySignature verifies
	VerifySignature(bub, digest, sig []byte) bool

	// Ecrecover a public key from a recoverable signature.
	Ecrecover(digest, sig []byte) ([]byte, error)
}

CipherSuite abstracts essential cryptographic primitives used by rrr. It exists principally to avoid licensing issues and circular dependencies on go-ethereum. Implementations are assumed to be EC secp256k1 + draft sha3. This interface does not allow for algorithmic agility of any kind.

type Config

type Config struct {
	IntentPhase  uint64 `toml:",omitempty"` // How long endorsers wait to decide the oldes leader
	ConfirmPhase uint64 `toml:",omitempty"` // Duration of the confirmation phase in milliseconds (must be < round)
	RoundLength  uint64 `toml:",omitempty"` // Duration of each round in milliseconds

	Candidates        uint64 `toml:",omitempty"` // Number of leader candidates (Nc) to propose from the oldest identities on each round
	Endorsers         uint64 `toml:",omitempty"` // Number of endorsers (Ne) to select from the most recently active identities
	Quorum            uint64 `toml:",omitempty"` // Number of endorsments required to confirm an intent
	Activity          uint64 `toml:",omitempty"` // Activity threshold (Ta) (in blocks). Any identity with confirmation messages recorded within this many rounds of the head are considered active.
	StablePrefixDepth uint64 `toml:"omitempty"`  // d stable block prefix (for seed r-d)

	// MinIdleAttempts if the identity is oldest for
	// MAX(Candidates,MinIdleAttempts) it is made idle. Used to avoid over
	// agressive idling in small networks.
	MinIdleAttempts uint64 `toml:"omitempty"`
	GossipFanout    int    `toml:"omitempty"`

	// ActivityMethod selects one of the alternative implementations for
	// tracking identity activity
	// sortendorsers - closest to paper, simplest implementation, may struggle with > 10000s of identities
	// sampleaged - maintains all idenities in age order all the time and does not sort in SelectActive
	ActivityMethod string `toml:"ommitempty"`
}

Config carries the RRR consensus configuration

type DRNG

type DRNG interface {
	Intn(n int) int
	NumSamplesRead() int
}

type Endorsement

type Endorsement struct {
	ChainID    Hash
	IntentHash Hash
	EndorserID Hash // NodeID of endorser
}

Endorsement represents the unsigned approval of a leader candidates intent.

type EndorsmentProtocol

type EndorsmentProtocol struct {
	T RoundTime

	Phase RoundPhase

	Number         uint64
	FailedAttempts uint32
	// contains filtered or unexported fields
}

EndorsmentProtocol implements 5.2 "Endorsement Protocol" and 5.3 "Chain Validation" (from the paper)

func NewRoundState

func NewRoundState(
	codec *CipherCodec, key *ecdsa.PrivateKey, config *Config, logger Logger,
) *EndorsmentProtocol

NewRoundState creates and initialises a RoundState

func (*EndorsmentProtocol) CalcDifficulty

func (r *EndorsmentProtocol) CalcDifficulty(nodeAddr Address) *big.Int

CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty that a new block should have. For rrr this is just the round number

func (*EndorsmentProtocol) CheckGenesis

func (r *EndorsmentProtocol) CheckGenesis(chain headerByNumberChainReader) error

CheckGenesis checks that the RRR consensus configuration in the genesis block is correct.

func (*EndorsmentProtocol) GetChainHeadRoundStart

func (r *EndorsmentProtocol) GetChainHeadRoundStart() time.Time

func (*EndorsmentProtocol) GetSealTime

func (r *EndorsmentProtocol) GetSealTime(header BlockHeader) (time.Time, error)

GetBlockTime returns the time the block was sealed. It decodes the extra data to do this. Consider caching the result.

func (*EndorsmentProtocol) IsEnrolmentPending

func (r *EndorsmentProtocol) IsEnrolmentPending(nodeID Hash) bool

IsEnrolmentPending returns true if there is an enrolment request queued for the nodeID

func (*EndorsmentProtocol) NewChainHead

func (r *EndorsmentProtocol) NewChainHead(
	b Broadcaster, chain EngineChainReader, head BlockHeader)

NewChainHead is called to handle the chainHead event from the block chain. For a block to make it this far, VerifyHeader and VerifySeal must have seen and accepted the block. A 'bad' block here is the result of a programming error.

func (*EndorsmentProtocol) NewSealTask

func (r *EndorsmentProtocol) NewSealTask(b Broadcaster, et *EngSealTask)

NewSealTask delivers work from the node to be mined. If we are the leader, and we are in the intent phase we immediately broadcast our intent. If not, we hang on to it until we are or we receive the next one.

func (*EndorsmentProtocol) NewSignedEndorsement

func (r *EndorsmentProtocol) NewSignedEndorsement(et *EngSignedEndorsement)

NewSignedEndorsement keeps track of endorsments received from peers. At the end of the confirmation phase, in PhaseTick, if we are a leader and our *current* intent has sufficient endorsments, we seal the block. This causes geth to broad cast it to the network.

func (*EndorsmentProtocol) NewSignedIntent

func (r *EndorsmentProtocol) NewSignedIntent(et *EngSignedIntent)

NewSignedIntent keeps track of the oldest intent seen in a round. At the end of the intent phase (in PhaseTick), if the node is an endorser, an endorsment is sent to the oldest seen. Only the most recent intent from any identity counts.

func (*EndorsmentProtocol) PhaseTick

func (r *EndorsmentProtocol) PhaseTick(b Broadcaster, chain EngineChainReader)

PhaseTick deals with the time based round state transitions. It MUST be called each time a tick is read from the ticker. At the end of the intent phase, if an endorser, the oldest seen intent is endorsed. At the end of the confirmation phase, if a leader candidate AND the current intent has sufficient endorsements, the block for the intent is sealed. Geth will then broadcast it.

func (*EndorsmentProtocol) PrimeActiveSelection

func (r *EndorsmentProtocol) PrimeActiveSelection(chain EngineChainReader) error

PrimeActiveSelection should be called for engine Start

func (*EndorsmentProtocol) QueueEnrolment

func (r *EndorsmentProtocol) QueueEnrolment(et *EngEnrolIdentity)

QueueEnrolment enrols a node id. This enrolment is completely open. The SGX identity attestation and the minining identity approaches are not presently included.

func (*EndorsmentProtocol) SetState

func (r *EndorsmentProtocol) SetState(state RoundState) RoundState

func (*EndorsmentProtocol) StableSeed

func (r *EndorsmentProtocol) StableSeed(chain EngineChainReader, headNumber uint64) (uint64, uint64, error)

func (*EndorsmentProtocol) StartRounds

func (r *EndorsmentProtocol) StartRounds(b Broadcaster, chain EngineChainReader)

StartRounds initialises the current round, establishes the current seed and starts the phase ticker. The engine run go routine calls this exactly once when it starts up.

func (*EndorsmentProtocol) State

func (r *EndorsmentProtocol) State() RoundState

func (*EndorsmentProtocol) UntilRoundEnd

func (r *EndorsmentProtocol) UntilRoundEnd() time.Duration

func (*EndorsmentProtocol) VerifyBranchHeaders

func (r *EndorsmentProtocol) VerifyBranchHeaders(
	chain VerifyBranchChainReader, header BlockHeader, parents []BlockHeader) error

func (*EndorsmentProtocol) VerifyHeader

func (r *EndorsmentProtocol) VerifyHeader(chain headerByHashChainReader, header BlockHeader) (*SignedExtraData, error)

type EngEnrolIdentity

type EngEnrolIdentity struct {
	NodeID [32]byte

	Round   uint64
	ReEnrol bool
}

type EngNewChainHead

type EngNewChainHead struct {
	BlockHeader BlockHeader
}

EngNewChainHead notifies the run loop of a NewChainHead event.

type EngSealTask

type EngSealTask struct {
	BlockHeader BlockHeader
	Committer   SealCommitter
	// RoundNumber the Seal was requested. Filled in by the endorsment protocol
	// when it retrieves the task of the run queue.
	RoundNumber uint64
}

EngSealTask is sent to the engines runningCh to request endorsment to create a block. This is initiated by the local miner invoking Seal interface method. If the local node is a leader candidate in the current round this will result in an Intent being broadcast. Otherwise it will be ignored by the engine. The miner will clear un-answered Seal requests when it sees a new chain head.

type EngSignedEndorsement

type EngSignedEndorsement struct {
	SignedEndorsement
	Pub []byte // Derived from signature
}

type EngSignedIntent

type EngSignedIntent struct {
	SignedIntent
	Pub []byte // Derived from signature
}

eng* types can be sent at any tome the the engines runningCh.

type Engine

type Engine struct {
	*EndorsmentProtocol
	// contains filtered or unexported fields
}

Engine implements consensus.Engine using Robust Round Robin consensus https://arxiv.org/abs/1804.07391

func NewEngine

func NewEngine(
	config *Config, codec *CipherCodec,
	privateKey *ecdsa.PrivateKey, logger Logger, opts ...EngineOption) (*Engine, error)

NewEngine a new instance of the rrr consensus engine. Assumes the provided engine instance is new.

func (*Engine) Author

func (e *Engine) Author(header BlockHeader) (Address, error)

Author retrieves the Ethereum address of the account that minted the given block, which may be different from the header's coinbase if a consensus engine is based on signatures.

func (*Engine) Broadcast

func (e *Engine) Broadcast(self Address, peers map[Address]Peer, msg []byte) error

Broadcast the message to the provided peers, skipping self. If we have previously sent the message to a peer, it is not resent.

func (*Engine) CalcDifficulty

func (e *Engine) CalcDifficulty(chain interface{}, time uint64, parent BlockHeader) *big.Int

CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty that a new block should have. For rrr this is just the round number

func (*Engine) ChainID

func (e *Engine) ChainID() Hash

ChainID is the chain identifier. Will return the zero hash until Start is called.

func (*Engine) FindPeers

func (e *Engine) FindPeers(
	peers map[Address]bool) map[Address]Peer

func (*Engine) HandleMsg

func (e *Engine) HandleMsg(peerAddr Address, msg []byte) (bool, error)

HandleMsg handles a message from peer and deals with gossiping consensus messages where necessary.

func (*Engine) IsEnrolmentPending

func (e *Engine) IsEnrolmentPending(nodeID [32]byte) bool

func (*Engine) IsRunning

func (e *Engine) IsRunning() bool

IsRunning returns true if the engine is still running

func (*Engine) NodeAddress

func (e *Engine) NodeAddress() Address

NodeAddress returns the node address

func (*Engine) NodeID

func (e *Engine) NodeID() Hash

func (*Engine) NodePublic

func (e *Engine) NodePublic() []byte

NodePublic returns the marshaled public key. (uncompressed form specified in section 4.3.6 of ANSI X9.62)

func (*Engine) PostIfRunning

func (e *Engine) PostIfRunning(i interface{}) bool

func (*Engine) RunLock

func (e *Engine) RunLock()

func (*Engine) RunUnlock

func (e *Engine) RunUnlock()

func (*Engine) Seal

func (e *Engine) Seal(blockHeader BlockHeader, sealCommitter SealCommitter) error

func (*Engine) Send

func (e *Engine) Send(peerAddr Address, rmsg RMsg) error

Send the message to the peer - if its hash is not in the ARU cache for the peer

func (*Engine) SendSignedEndorsement

func (e *Engine) SendSignedEndorsement(intenderAddr Address, et *EngSignedIntent) error

SendSignedEndorsement sends a signed (endorsed) intent back to the intender

func (*Engine) SetPeerFinder

func (e *Engine) SetPeerFinder(f PeerFinder)

SetBroadcaster implements consensus.Handler.SetBroadcaster Which, for the quorum fork, is called by eth/handler.go NewProtocolManager

func (*Engine) Start

func (e *Engine) Start(
	chain EngineChainReader, withLock WithLock) error

Start the consensus protocol. To allow for atomic cleanup, the caller provided withLock is invoked as soon as the lock is aquired. Note that withLock is *always* called if it is not nil - regardless of whether the engine is already started.

func (*Engine) Stop

func (e *Engine) Stop(withLock WithLock)

Stop stops the engine. To allow for atomic cleanup, the caller provided withLock is invoked as soon as the lock is aquired.

func (*Engine) VerifyBranchHeaders

func (e *Engine) VerifyBranchHeaders(
	chain VerifyBranchChainReader, header BlockHeader, parents []BlockHeader) error

func (*Engine) VerifyHeader

func (e *Engine) VerifyHeader(chain headerByHashChainReader, header BlockHeader) error

func (*Engine) VerifySeal

func (e *Engine) VerifySeal(chain VerifyBranchChainReader, header BlockHeader) error

type EngineChainReader

type EngineChainReader interface {
	CurrentHeader() BlockHeader
	GetHeaderByNumber(number uint64) BlockHeader
	GetHeaderByHash(hash [32]byte) BlockHeader
}

type EngineOption

type EngineOption func(e *Engine)

func WithClockCheck

func WithClockCheck(checker func()) EngineOption

type Enrolment

type Enrolment struct {
	Q Quote
	U Hash // nodeid for genesis, EnrolmentBinding.U() otherwise

	// ID can be verified by reconstructing an EnrolmentBinding, getting its
	// hash, comparing that hash with U (above) and then checking that the
	// public key for the node that sealed the block with the Enrolment can
	// verify the quote.
	ID Hash // must be verified by re-creating an Enrol
}

Enrolment provides the RRR identity enrolment data.

func IdentInit

func IdentInit(
	codec *CipherCodec, ck *ecdsa.PrivateKey, init []Enrolment, nodeids ...Hash) ([]Enrolment, error)

IdentInit creates, or extends, the identity initialisation vector for the extraData in the genesis block. init is nil or the currently included identities. One or more nodeids are passed as the trailing parameters. The updated init vector is returned. See EIP-rrr/extraData of Block0

type EnrolmentBinding

type EnrolmentBinding struct {
	ChainID   Hash   // ChainID is EIP-rrr/extraData of Block0
	NodeID    Hash   // NodeID is defined by ethereum as keccak 256 ( PublicKey X || Y )
	Round     uint64 // Round is the consensus round
	BlockHash Hash   // BlockHash is the block hash for the head of the selected chain branch
	ReEnrol   bool   // true if the identity has been enroled before.
}

EnrolmentBinding is rlp encoded, hashed and signed to introduce NodeID as a member.

type ExtraData

type ExtraData struct {
	ExtraHeader
	Intent  Intent
	Confirm []Endorsement
}

ExtraData is the complete (minus sig) RRR consensus data included on each block

type ExtraHeader

type ExtraHeader struct {
	SealTime []byte // result of time.Now().UTC().MarshalBinary() at seal time
	Seed     []byte // VRF beta output, alpha is previous seed
	Proof    []byte // VRF proof
	Enrol    []Enrolment
}

ExtraHeader is the common header for the genesis block and consensus produced blocks

type GenesisExtraData

type GenesisExtraData struct {
	ChainInit
	ChainID Hash // Hash of encoded ChainInit
}

GenesisExtraData adds the ChainID which is the hash of the ChainInit

type Hash

type Hash [32]byte

Hash is a hash. We always work with Keccak256 (draft sha3)

func Hex2Hash

func Hex2Hash(s string) Hash

func Keccak256Hash

func Keccak256Hash(c CipherSuite, b ...[]byte) Hash

Keccak256Hash hashes a variable number of byte slices and returns a Hash

func NodeIDFromPub

func NodeIDFromPub(c CipherSuite, pub *ecdsa.PublicKey) Hash

NodeIDFromPub gets a node id from an ecdsa pub key

func NodeIDFromPubBytes

func NodeIDFromPubBytes(c CipherSuite, pub []byte) (Hash, error)

NodeIDFromPubBytes gets a node id from the bytes of an ecdsa public key

func (Hash) Address

func (h Hash) Address() Address

Address gets an address from a hash

func (Hash) EnodeIDFromSig

func (h Hash) EnodeIDFromSig(c CipherSuite, sig []byte) ([]byte, error)

EnodeIDFromSig recovers the enode id for the signer of the hash

func (Hash) Hex

func (h Hash) Hex() string

Hex gets the hex string of the Hash

func (Hash) NodeIDFromSig

func (h Hash) NodeIDFromSig(c CipherSuite, sig []byte) (Hash, error)

NodeIDFromSig gets the recovers the signers node id from the signature

func (Hash) SignerPub

func (h Hash) SignerPub(c CipherSuite, sig []byte) (*ecdsa.PublicKey, error)

SignerPub recovers the public key that signed h

type Intent

type Intent struct {
	// ChainID is established in the extradata of the genesis block
	ChainID Hash
	// NodeID is Keccak256 ( PublicKey X || Y )
	NodeID Hash

	// RoundNumber is the block number proposed.
	RoundNumber uint64
	// ParentHash parent block hash
	ParentHash Hash
	// TxHash is the hash of the transactions (merkle root for block)
	TxHash Hash
}

Intent declares a leader candidates intent to seal a block

type Logger

type Logger interface {
	LazyValue(func() string) interface{}
	Trace(msg string, ctx ...interface{})
	Debug(msg string, ctx ...interface{})
	Info(msg string, ctx ...interface{})
	Warn(msg string, ctx ...interface{})
	Crit(msg string, ctx ...interface{})
}

Logger is the go-ethereum compatible logging interface used in rrr

type Participant

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

type ParticipantByAge

type ParticipantByAge []*Participant

func (ParticipantByAge) Len

func (a ParticipantByAge) Len() int

func (ParticipantByAge) Less

func (a ParticipantByAge) Less(i, j int) bool

func (ParticipantByAge) Swap

func (a ParticipantByAge) Swap(i, j int)

type ParticipantByID

type ParticipantByID []*Participant

func (ParticipantByID) Len

func (a ParticipantByID) Len() int

func (ParticipantByID) Less

func (a ParticipantByID) Less(i, j int) bool

func (ParticipantByID) Swap

func (a ParticipantByID) Swap(i, j int)

type Peer

type Peer interface {

	// SendConsensus sends a consensus message to this peer
	SendConsensus(data interface{}) error
}

type PeerFinder

type PeerFinder interface {
	FindPeers(map[Address]bool) map[Address]Peer
}

type Quote

type Quote [65]byte

Quote is the 'pseudo' attestation of identity performed using node private keys rather than SGX. See RRR-spec 'extraData of Block0' and 'Enrolment data'. It is only the "Quote" refrenced in the original paper in so far as it will be the Qi that gets included in Block0 or in Enroln messages. It's an ecdsa signature the [R || S || V] format

type RMsg

type RMsg struct {
	Code RMsgCode
	Raw  []byte

	Round uint64

	// If the message is to be gossiped, To are the intended recipients. Any
	// node that has a direct connection for any To address will simply send
	// directly, remove it from the To list, and only re-broadcast if any To's
	// remain. Note that in any given round we are only gossiping RMsgIntent's or
	// RMsgConfirm's. And we are only gossiping amongst leader candidates and
	// endorsers selected for the current round - not the entire network.
	To []Address

	// telemetry only, incremented each time the message is re-gossiped
	PathLength uint32
}

RMsg is the dev p2p (eth) message for RRR

type RMsgCode

type RMsgCode uint

RMsgCode identifies the rrr message type. rrrMsg identifies rrr's message type to the devp2p layer as being consensus engine specific. Once that outer message is delivered to rrr, RMsgCode is how rrr differentiates each of its supported message payloads.

const (
	// RMsgInvalid is the *never set* invalid message code
	RMsgInvalid RMsgCode = iota
	// RMsgIntent identifies RRR intent messages
	RMsgIntent
	// RMsgConfirm identifies RRR endorsement messages (confirmations)
	RMsgConfirm

	// RMsgEnrol is used to alow nodes to self enrol and automatically re-enrol
	// without needing to go through the rpc mechanism
	RMsgEnrol

	// RMsgRandContribSolicit ...
	RMsgRandContribSolicit
	// RMsgRandContrib ...
	RMsgRandContrib
	// RMsgRandAgreementSolicit ...
	RMsgRandAgreementSolicit
	// RMsgRandAgreement ...
	RMsgRandAgreement
)

func (RMsgCode) String

func (c RMsgCode) String() string

type RoundPhase

type RoundPhase int

RoundPhase is the type for the round phase

const (
	// RoundPhaseInvalid is the invalid state for RoundPhase
	RoundPhaseInvalid RoundPhase = iota
	// RoundPhaseIntent During the Intent phase, the endorser committee is
	// allowing for intents to arrive so they can, with high probability, pick
	// the oldest active leader candidate.
	RoundPhaseIntent
	// RoundPhaseConfirm During the confirmation phase leaders are waiting for
	// all the endorsements to come in so they fairly represent activity.
	RoundPhaseConfirm

	// RoundPhaseBroadcast during the Broadcast phase all nodes are waiting for
	// a NewChainHead event for the current round (including the c nsensus
	// leaders). Any node receiving an otherwise valid HEAD for a different
	// round must align with the round on the recieved head.
	RoundPhaseBroadcast

	// Used to absorb and align the start time with the round time. Means we
	// can deal with most initialisation the same as we do the end of the
	// Broadcast round *and* we may get a block while we wait.
	RoundPhaseStartup
)

func (RoundPhase) String

func (p RoundPhase) String() string

Home for stringers and other telemetry related distractions

type RoundState

type RoundState int

RoundState type for the round state

const (
	// RoundStateInvalid is the invalid and never set state
	RoundStateInvalid RoundState = iota
	// RoundStateInactive is set if the node is not in the active selection for the round.
	RoundStateInactive // Indicates conditions we expect to be transitor - endorsers not online etc

	// RoundStateActive is entered if the node is active but is not selected as
	// either a leader or an endorser
	RoundStateActive // Has endorsed or mined in some time in the last Ta rounds.

	// RoundStateLeaderCandidate selected as leader candidate for current round
	RoundStateLeaderCandidate
	// RoundStateEndorserCommittee Is in the endorser committee for the current round.
	RoundStateEndorserCommittee
)

func (RoundState) String

func (s RoundState) String() string

type RoundTime

type RoundTime struct {
	Confirm     time.Duration
	Intent      time.Duration
	Broadcast   time.Duration
	RoundLength time.Duration

	Ticker *time.Timer
}

RoundTime takes (some) of the sharp edges of go's time.Timer and provides conveniences for manaing the time based RRR state

func NewRoundTime

func NewRoundTime(
	config *Config, opts ...RoundTimeOption) RoundTime

NewRoundTime creates and configures a RoundTime. Does *not* call Start

func (*RoundTime) Reset

func (t *RoundTime) Reset(d time.Duration)

Reset resets for an arbitrary duration

func (*RoundTime) ResetForBroadcastPhase

func (t *RoundTime) ResetForBroadcastPhase()

func (*RoundTime) ResetForConfirmPhase

func (t *RoundTime) ResetForConfirmPhase()

ResetForConfirmPhase resets the ticker appropriately for begining the confirm phase (without adjustment). Be very careful to call StopTicker exactly once before calling this.

func (*RoundTime) ResetForIntentPhase

func (t *RoundTime) ResetForIntentPhase()

ResetForIntentPhase resets the ticker appropriately for begining the intent phase (without adjustment). Be very careful to call StopTicker exactly once before calling this.

func (*RoundTime) Start

func (t *RoundTime) Start(offset time.Duration)

func (*RoundTime) Stop

func (t *RoundTime) Stop()

Stop stops and, if necessary, drains the ticker

type RoundTimeOption

type RoundTimeOption func(r *RoundTime)

type SealCommitter

type SealCommitter interface {
	CurrentBlockHash() [32]byte
	CommitSeal([]byte)
	Canceled() bool
}

type SignedEndorsement

type SignedEndorsement struct {
	Endorsement
	// Sig is the ecdsa signature the [R || S || V] format
	Sig [65]byte
}

SignedEndorsement is the approval with the appropriate sig

type SignedExtraData

type SignedExtraData struct {
	ExtraData
	// Sig is the ecdsa signature the [R || S || V] format
	Sig [65]byte
}

SignedExtraData is ExtraData with signature

type SignedExtraDecoder

type SignedExtraDecoder interface {
	DecodeSignedExtraData(se *SignedExtraData, b []byte) ([]byte, error)
}

type SignedIntent

type SignedIntent struct {
	Intent
	// Sig is the ecdsa signature the [R || S || V] format
	Sig [65]byte
}

SignedIntent holds the Intent plus its sig

type VerifyBranchChainReader

type VerifyBranchChainReader interface {

	// GetHeader retrieves a block header from the database by hash and number.
	GetHeader(hash [32]byte, number uint64) BlockHeader

	// GetHeaderByNumber retrieves a block header from the database by number.
	GetHeaderByNumber(number uint64) BlockHeader
	// GetHeaderByNumber retrieves a block header from the database by number.
	GetHeaderByHash(hash [32]byte) BlockHeader
}

type WithLock

type WithLock func()

Jump to

Keyboard shortcuts

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