runner

package
v1.3.3 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2024 License: GPL-3.0 Imports: 31 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AggregatorRunner

type AggregatorRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

func (*AggregatorRunner) Decode

func (r *AggregatorRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*AggregatorRunner) Encode

func (r *AggregatorRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*AggregatorRunner) GetBaseRunner

func (r *AggregatorRunner) GetBaseRunner() *BaseRunner

func (*AggregatorRunner) GetBeaconNode

func (r *AggregatorRunner) GetBeaconNode() specssv.BeaconNode

func (*AggregatorRunner) GetNetwork

func (r *AggregatorRunner) GetNetwork() specssv.Network

func (*AggregatorRunner) GetRoot

func (r *AggregatorRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification GetRoot returns the root used for signing and verification

func (*AggregatorRunner) GetShare

func (r *AggregatorRunner) GetShare() *spectypes.Share

func (*AggregatorRunner) GetSigner

func (r *AggregatorRunner) GetSigner() spectypes.KeyManager

func (*AggregatorRunner) GetState

func (r *AggregatorRunner) GetState() *State

func (*AggregatorRunner) GetValCheckF

func (r *AggregatorRunner) GetValCheckF() specqbft.ProposedValueCheckF

func (*AggregatorRunner) HasRunningDuty

func (r *AggregatorRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*AggregatorRunner) ProcessConsensus

func (r *AggregatorRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*AggregatorRunner) ProcessPostConsensus

func (r *AggregatorRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*AggregatorRunner) ProcessPreConsensus

func (r *AggregatorRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*AggregatorRunner) StartNewDuty

func (r *AggregatorRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type AttesterRunner

type AttesterRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

func (*AttesterRunner) Decode

func (r *AttesterRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*AttesterRunner) Encode

func (r *AttesterRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*AttesterRunner) GetBaseRunner

func (r *AttesterRunner) GetBaseRunner() *BaseRunner

func (*AttesterRunner) GetBeaconNode

func (r *AttesterRunner) GetBeaconNode() specssv.BeaconNode

func (*AttesterRunner) GetNetwork

func (r *AttesterRunner) GetNetwork() specssv.Network

func (*AttesterRunner) GetRoot

func (r *AttesterRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*AttesterRunner) GetShare

func (r *AttesterRunner) GetShare() *spectypes.Share

func (*AttesterRunner) GetSigner

func (r *AttesterRunner) GetSigner() spectypes.KeyManager

func (*AttesterRunner) GetState

func (r *AttesterRunner) GetState() *State

func (*AttesterRunner) GetValCheckF

func (r *AttesterRunner) GetValCheckF() specqbft.ProposedValueCheckF

func (*AttesterRunner) HasRunningDuty

func (r *AttesterRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*AttesterRunner) ProcessConsensus

func (r *AttesterRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*AttesterRunner) ProcessPostConsensus

func (r *AttesterRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*AttesterRunner) ProcessPreConsensus

func (r *AttesterRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*AttesterRunner) StartNewDuty

func (r *AttesterRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type BaseRunner

type BaseRunner struct {
	State          *State
	Share          *spectypes.Share
	QBFTController *controller.Controller
	BeaconNetwork  spectypes.BeaconNetwork
	BeaconRoleType spectypes.BeaconRole

	// implementation vars
	TimeoutF TimeoutF `json:"-"`
	// contains filtered or unexported fields
}

func NewBaseRunner

func NewBaseRunner(
	state *State,
	share *spectypes.Share,
	controller *controller.Controller,
	beaconNetwork spectypes.BeaconNetwork,
	beaconRoleType spectypes.BeaconRole,
	highestDecidedSlot spec.Slot,
) *BaseRunner

func (*BaseRunner) FallBackAndVerifyEachSignature added in v1.3.3

func (b *BaseRunner) FallBackAndVerifyEachSignature(container *specssv.PartialSigContainer, root [32]byte)

Verify each signature in container removing the invalid ones

func (*BaseRunner) SetHighestDecidedSlot added in v1.1.0

func (b *BaseRunner) SetHighestDecidedSlot(slot spec.Slot)

SetHighestDecidedSlot set highestDecidedSlot for base runner

func (*BaseRunner) ShouldProcessDuty added in v1.1.0

func (b *BaseRunner) ShouldProcessDuty(duty *spectypes.Duty) error

func (*BaseRunner) ShouldProcessNonBeaconDuty added in v1.1.0

func (b *BaseRunner) ShouldProcessNonBeaconDuty(duty *spectypes.Duty) error

func (*BaseRunner) ValidatePostConsensusMsg

func (b *BaseRunner) ValidatePostConsensusMsg(runner Runner, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*BaseRunner) ValidatePreConsensusMsg

func (b *BaseRunner) ValidatePreConsensusMsg(runner Runner, signedMsg *spectypes.SignedPartialSignatureMessage) error

type DutyRunners

type DutyRunners map[spectypes.BeaconRole]Runner

DutyRunners is a map of duty runners mapped by msg id hex.

func (DutyRunners) DutyRunnerForMsgID

func (ci DutyRunners) DutyRunnerForMsgID(msgID spectypes.MessageID) Runner

DutyRunnerForMsgID returns a Runner from the provided msg ID, or nil if not found

type Getters

type Getters interface {
	GetBaseRunner() *BaseRunner
	GetBeaconNode() specssv.BeaconNode
	GetValCheckF() specqbft.ProposedValueCheckF
	GetSigner() spectypes.KeyManager
	GetNetwork() specssv.Network
}

type ProposerRunner

type ProposerRunner struct {
	BaseRunner *BaseRunner
	// ProducesBlindedBlocks is true when the runner will only produce blinded blocks
	ProducesBlindedBlocks bool
	// contains filtered or unexported fields
}

func (*ProposerRunner) Decode

func (r *ProposerRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*ProposerRunner) Encode

func (r *ProposerRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*ProposerRunner) GetBaseRunner

func (r *ProposerRunner) GetBaseRunner() *BaseRunner

func (*ProposerRunner) GetBeaconNode

func (r *ProposerRunner) GetBeaconNode() specssv.BeaconNode

func (*ProposerRunner) GetNetwork

func (r *ProposerRunner) GetNetwork() specssv.Network

func (*ProposerRunner) GetRoot

func (r *ProposerRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*ProposerRunner) GetShare

func (r *ProposerRunner) GetShare() *spectypes.Share

func (*ProposerRunner) GetSigner

func (r *ProposerRunner) GetSigner() spectypes.KeyManager

func (*ProposerRunner) GetState

func (r *ProposerRunner) GetState() *State

func (*ProposerRunner) GetValCheckF

func (r *ProposerRunner) GetValCheckF() specqbft.ProposedValueCheckF

func (*ProposerRunner) HasRunningDuty

func (r *ProposerRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*ProposerRunner) ProcessConsensus

func (r *ProposerRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*ProposerRunner) ProcessPostConsensus

func (r *ProposerRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*ProposerRunner) ProcessPreConsensus

func (r *ProposerRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*ProposerRunner) StartNewDuty

func (r *ProposerRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type Runner

type Runner interface {
	spectypes.Encoder
	spectypes.Root
	Getters

	// StartNewDuty starts a new duty for the runner, returns error if can't
	StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error
	// HasRunningDuty returns true if it has a running duty
	HasRunningDuty() bool
	// ProcessPreConsensus processes all pre-consensus msgs, returns error if can't process
	ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error
	// ProcessConsensus processes all consensus msgs, returns error if can't process
	ProcessConsensus(logger *zap.Logger, msg *specqbft.SignedMessage) error
	// ProcessPostConsensus processes all post-consensus msgs, returns error if can't process
	ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error
	// contains filtered or unexported methods
}

func NewAggregatorRunner

func NewAggregatorRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
	valCheck specqbft.ProposedValueCheckF,
	highestDecidedSlot phase0.Slot,
) Runner

func NewAttesterRunnner

func NewAttesterRunnner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
	valCheck specqbft.ProposedValueCheckF,
	highestDecidedSlot phase0.Slot,
) Runner

func NewProposerRunner

func NewProposerRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
	valCheck specqbft.ProposedValueCheckF,
	highestDecidedSlot phase0.Slot,
) Runner

func NewSyncCommitteeAggregatorRunner

func NewSyncCommitteeAggregatorRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
	valCheck specqbft.ProposedValueCheckF,
	highestDecidedSlot phase0.Slot,
) Runner

func NewSyncCommitteeRunner

func NewSyncCommitteeRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
	valCheck specqbft.ProposedValueCheckF,
	highestDecidedSlot phase0.Slot,
) Runner

func NewValidatorRegistrationRunner

func NewValidatorRegistrationRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	qbftController *controller.Controller,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
) Runner

func NewVoluntaryExitRunner added in v1.1.0

func NewVoluntaryExitRunner(
	beaconNetwork spectypes.BeaconNetwork,
	share *spectypes.Share,
	beacon specssv.BeaconNode,
	network specssv.Network,
	signer spectypes.KeyManager,
) Runner

type State

type State struct {
	PreConsensusContainer  *specssv.PartialSigContainer
	PostConsensusContainer *specssv.PartialSigContainer
	RunningInstance        *instance.Instance
	DecidedValue           *spectypes.ConsensusData
	// CurrentDuty is the duty the node pulled locally from the beacon node, might be different from decided duty
	StartingDuty *spectypes.Duty
	// flags
	Finished bool // Finished marked true when there is a full successful cycle (pre, consensus and post) with quorum
}

State holds all the relevant progress the duty execution progress

func NewRunnerState

func NewRunnerState(quorum uint64, duty *spectypes.Duty) *State

func (*State) Decode

func (pcs *State) Decode(data []byte) error

Decode returns error if decoding failed

func (*State) Encode

func (pcs *State) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*State) GetRoot

func (pcs *State) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*State) ReconstructBeaconSig

func (pcs *State) ReconstructBeaconSig(container *specssv.PartialSigContainer, root [32]byte, validatorPubKey []byte) ([]byte, error)

ReconstructBeaconSig aggregates collected partial beacon sigs

type SyncCommitteeAggregatorRunner

type SyncCommitteeAggregatorRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

func (*SyncCommitteeAggregatorRunner) Decode

func (r *SyncCommitteeAggregatorRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*SyncCommitteeAggregatorRunner) Encode

func (r *SyncCommitteeAggregatorRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*SyncCommitteeAggregatorRunner) GetBaseRunner

func (r *SyncCommitteeAggregatorRunner) GetBaseRunner() *BaseRunner

func (*SyncCommitteeAggregatorRunner) GetBeaconNode

func (*SyncCommitteeAggregatorRunner) GetNetwork

func (*SyncCommitteeAggregatorRunner) GetRoot

func (r *SyncCommitteeAggregatorRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*SyncCommitteeAggregatorRunner) GetShare

func (*SyncCommitteeAggregatorRunner) GetSigner

func (*SyncCommitteeAggregatorRunner) GetState

func (r *SyncCommitteeAggregatorRunner) GetState() *State

func (*SyncCommitteeAggregatorRunner) GetValCheckF

func (*SyncCommitteeAggregatorRunner) HasRunningDuty

func (r *SyncCommitteeAggregatorRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*SyncCommitteeAggregatorRunner) ProcessConsensus

func (r *SyncCommitteeAggregatorRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*SyncCommitteeAggregatorRunner) ProcessPostConsensus

func (r *SyncCommitteeAggregatorRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*SyncCommitteeAggregatorRunner) ProcessPreConsensus

func (r *SyncCommitteeAggregatorRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*SyncCommitteeAggregatorRunner) StartNewDuty

func (r *SyncCommitteeAggregatorRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type SyncCommitteeRunner

type SyncCommitteeRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

func (*SyncCommitteeRunner) Decode

func (r *SyncCommitteeRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*SyncCommitteeRunner) Encode

func (r *SyncCommitteeRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*SyncCommitteeRunner) GetBaseRunner

func (r *SyncCommitteeRunner) GetBaseRunner() *BaseRunner

func (*SyncCommitteeRunner) GetBeaconNode

func (r *SyncCommitteeRunner) GetBeaconNode() specssv.BeaconNode

func (*SyncCommitteeRunner) GetNetwork

func (r *SyncCommitteeRunner) GetNetwork() specssv.Network

func (*SyncCommitteeRunner) GetRoot

func (r *SyncCommitteeRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*SyncCommitteeRunner) GetShare

func (r *SyncCommitteeRunner) GetShare() *spectypes.Share

func (*SyncCommitteeRunner) GetSigner

func (r *SyncCommitteeRunner) GetSigner() spectypes.KeyManager

func (*SyncCommitteeRunner) GetState

func (r *SyncCommitteeRunner) GetState() *State

func (*SyncCommitteeRunner) GetValCheckF

func (*SyncCommitteeRunner) HasRunningDuty

func (r *SyncCommitteeRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*SyncCommitteeRunner) ProcessConsensus

func (r *SyncCommitteeRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*SyncCommitteeRunner) ProcessPostConsensus

func (r *SyncCommitteeRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*SyncCommitteeRunner) ProcessPreConsensus

func (r *SyncCommitteeRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*SyncCommitteeRunner) StartNewDuty

func (r *SyncCommitteeRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type TimeoutF

type TimeoutF func(logger *zap.Logger, identifier spectypes.MessageID, height specqbft.Height) roundtimer.OnRoundTimeoutF

type ValidatorRegistrationRunner

type ValidatorRegistrationRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

func (*ValidatorRegistrationRunner) Decode

func (r *ValidatorRegistrationRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*ValidatorRegistrationRunner) Encode

func (r *ValidatorRegistrationRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*ValidatorRegistrationRunner) GetBaseRunner

func (r *ValidatorRegistrationRunner) GetBaseRunner() *BaseRunner

func (*ValidatorRegistrationRunner) GetBeaconNode

func (r *ValidatorRegistrationRunner) GetBeaconNode() specssv.BeaconNode

func (*ValidatorRegistrationRunner) GetNetwork

func (*ValidatorRegistrationRunner) GetRoot

func (r *ValidatorRegistrationRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*ValidatorRegistrationRunner) GetShare

func (*ValidatorRegistrationRunner) GetSigner

func (*ValidatorRegistrationRunner) GetState

func (r *ValidatorRegistrationRunner) GetState() *State

func (*ValidatorRegistrationRunner) GetValCheckF

func (*ValidatorRegistrationRunner) HasRunningDuty

func (r *ValidatorRegistrationRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*ValidatorRegistrationRunner) ProcessConsensus

func (r *ValidatorRegistrationRunner) ProcessConsensus(logger *zap.Logger, signedMsg *qbft.SignedMessage) error

func (*ValidatorRegistrationRunner) ProcessPostConsensus

func (r *ValidatorRegistrationRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*ValidatorRegistrationRunner) ProcessPreConsensus

func (r *ValidatorRegistrationRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*ValidatorRegistrationRunner) StartNewDuty

func (r *ValidatorRegistrationRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

type VoluntaryExitRunner added in v1.1.0

type VoluntaryExitRunner struct {
	BaseRunner *BaseRunner
	// contains filtered or unexported fields
}

Duty runner for validator voluntary exit duty

func (*VoluntaryExitRunner) Decode added in v1.1.0

func (r *VoluntaryExitRunner) Decode(data []byte) error

Decode returns error if decoding failed

func (*VoluntaryExitRunner) Encode added in v1.1.0

func (r *VoluntaryExitRunner) Encode() ([]byte, error)

Encode returns the encoded struct in bytes or error

func (*VoluntaryExitRunner) GetBaseRunner added in v1.1.0

func (r *VoluntaryExitRunner) GetBaseRunner() *BaseRunner

func (*VoluntaryExitRunner) GetBeaconNode added in v1.1.0

func (r *VoluntaryExitRunner) GetBeaconNode() specssv.BeaconNode

func (*VoluntaryExitRunner) GetNetwork added in v1.1.0

func (r *VoluntaryExitRunner) GetNetwork() specssv.Network

func (*VoluntaryExitRunner) GetRoot added in v1.1.0

func (r *VoluntaryExitRunner) GetRoot() ([32]byte, error)

GetRoot returns the root used for signing and verification

func (*VoluntaryExitRunner) GetShare added in v1.1.0

func (r *VoluntaryExitRunner) GetShare() *spectypes.Share

func (*VoluntaryExitRunner) GetSigner added in v1.1.0

func (r *VoluntaryExitRunner) GetSigner() spectypes.KeyManager

func (*VoluntaryExitRunner) GetState added in v1.1.0

func (r *VoluntaryExitRunner) GetState() *State

func (*VoluntaryExitRunner) GetValCheckF added in v1.1.0

func (*VoluntaryExitRunner) HasRunningDuty added in v1.1.0

func (r *VoluntaryExitRunner) HasRunningDuty() bool

HasRunningDuty returns true if a duty is already running (StartNewDuty called and returned nil)

func (*VoluntaryExitRunner) ProcessConsensus added in v1.1.0

func (r *VoluntaryExitRunner) ProcessConsensus(logger *zap.Logger, signedMsg *specqbft.SignedMessage) error

func (*VoluntaryExitRunner) ProcessPostConsensus added in v1.1.0

func (r *VoluntaryExitRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

func (*VoluntaryExitRunner) ProcessPreConsensus added in v1.1.0

func (r *VoluntaryExitRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spectypes.SignedPartialSignatureMessage) error

Check for quorum of partial signatures over VoluntaryExit and, if has quorum, constructs SignedVoluntaryExit and submits to BeaconNode

func (*VoluntaryExitRunner) StartNewDuty added in v1.1.0

func (r *VoluntaryExitRunner) StartNewDuty(logger *zap.Logger, duty *spectypes.Duty) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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