fch

package
v0.0.0-...-3a5d5d8 Latest Latest
Warning

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

Go to latest
Published: Mar 13, 2024 License: LGPL-3.0 Imports: 51 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// BloomBitsBlocks is the number of blocks a single bloom bit section vector
	// contains on the server side.
	BloomBitsBlocks uint64 = 4096
)

Variables

View Source
var DefaultMaxPrice = big.NewInt(1 * params.Ether)
View Source
var (
	// ErrFinalizedTransaction is returned if the transaction to be submitted is already on-chain
	ErrFinalizedTransaction = errors.New("transaction already finalized")
)

Functions

func NewBloomIndexer

func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *core.ChainIndexer

NewBloomIndexer returns a chain indexer that generates bloom bits data for the canonical chain for fast logs filtering.

Types

type BloomIndexer

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

BloomIndexer implements a core.ChainIndexer, building up a rotated bloom bits index for the Ethereum header bloom filters, permitting blazing fast filtering.

func (*BloomIndexer) Commit

func (b *BloomIndexer) Commit() error

Commit implements core.ChainIndexerBackend, finalizing the bloom section and writing it out into the database.

func (*BloomIndexer) Process

func (b *BloomIndexer) Process(ctx context.Context, header *block.Header) error

Process implements core.ChainIndexerBackend, adding a new header's bloom into the index.

func (*BloomIndexer) Reset

func (b *BloomIndexer) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error

Reset implements core.ChainIndexerBackend, starting a new bloombits index section.

type DetailedBlockSignerInfo

type DetailedBlockSignerInfo struct {
	// Signers are all the signers for the block
	Signers shard.SlotList
	// Committee when the block was signed.
	Committee shard.SlotList
	BlockHash common.Hash
}

DetailedBlockSignerInfo contains all of the block singing information

type ExecutionResult

type ExecutionResult struct {
	Gas         uint64         `json:"gas"`
	Failed      bool           `json:"failed"`
	ReturnValue string         `json:"returnValue"`
	StructLogs  []StructLogRes `json:"structLogs"`
}

ExecutionResult groups all structured logs emitted by the EVM while replaying a transaction in debug mode as well as transaction execution status, the amount of gas used and the return value Taken from go-ethereum/internal/ethapi/api.go

type Feechain

type Feechain struct {
	// Channel for shutting down the service
	ShutdownChan  chan bool                      // Channel for shutting down the Feechain
	BloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
	BlockChain    *core.BlockChain
	BeaconChain   *core.BlockChain
	TxPool        *core.TxPool
	CxPool        *core.CxPool // CxPool is used to store the blockHashes of blocks containing cx receipts to be sent
	// DB interfaces
	BloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
	NodeAPI      NodeAPI
	// ChainID is used to identify which network we are using
	ChainID uint64
	// EthCompatibleChainID is used to identify the Ethereum compatible chain ID
	EthChainID uint64
	// RPCGasCap is the global gas cap for eth-call variants.
	RPCGasCap *big.Int `toml:",omitempty"`
	ShardID   uint32
	// contains filtered or unexported fields
}

Feechain implements the Feechain full node service.

func New

func New(
	nodeAPI NodeAPI, txPool *core.TxPool, cxPool *core.CxPool, shardID uint32,
) *Feechain

New creates a new Feechain object (including the initialisation of the common Feechain object)

func (*Feechain) BlockByNumber

func (fch *Feechain) BlockByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*types.Block, error)

BlockByNumber ...

func (*Feechain) BloomStatus

func (fch *Feechain) BloomStatus() (uint64, uint64)

BloomStatus ... TODO: this is not implemented or verified yet for feechain.

func (*Feechain) ChainConfig

func (fch *Feechain) ChainConfig() *params.ChainConfig

ChainConfig ...

func (*Feechain) ChainDb

func (fch *Feechain) ChainDb() ethdb.Database

ChainDb ..

func (*Feechain) ComputeStateDB

func (fch *Feechain) ComputeStateDB(block *types.Block, reexec uint64) (*state.DB, error)

ComputeStateDB retrieves the state database associated with a certain block. If no state is locally available for the given block, a number of blocks are attempted to be reexecuted to generate the desired state.

func (*Feechain) ComputeTxEnv

func (fch *Feechain) ComputeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.Context, *state.DB, error)

ComputeTxEnv returns the execution environment of a certain transaction.

func (*Feechain) ComputeTxEnvEachBlockWithoutApply

func (fch *Feechain) ComputeTxEnvEachBlockWithoutApply(block *types.Block, reexec uint64, cb func(int, *types.Transaction, core.Message, vm.Context, *state.DB) bool) error

ComputeTxEnvEachBlockWithoutApply returns the execution environment of a certain transaction.

func (*Feechain) CurrentBlock

func (fch *Feechain) CurrentBlock() *types.Block

CurrentBlock ...

func (*Feechain) EventMux

func (fch *Feechain) EventMux() *event.TypeMux

EventMux ..

func (*Feechain) GetAccountNonce

func (fch *Feechain) GetAccountNonce(
	ctx context.Context, address common.Address, blockNum rpc.BlockNumber) (uint64, error)

GetAccountNonce returns the nonce value of the given address for the given block number

func (*Feechain) GetAllValidatorAddresses

func (fch *Feechain) GetAllValidatorAddresses() []common.Address

GetAllValidatorAddresses returns the up to date validator candidates for next epoch

func (*Feechain) GetBalance

func (fch *Feechain) GetBalance(ctx context.Context, address common.Address, blockNum rpc.BlockNumber) (*big.Int, error)

GetBalance returns balance of an given address.

func (*Feechain) GetBlock

func (fch *Feechain) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error)

GetBlock ...

func (*Feechain) GetBlockSigners

func (fch *Feechain) GetBlockSigners(
	ctx context.Context, blockNum rpc.BlockNumber,
) (shard.SlotList, *internal_bls.Mask, error)

GetBlockSigners ..

func (*Feechain) GetCurrentBadBlocks

func (fch *Feechain) GetCurrentBadBlocks() []core.BadBlock

GetCurrentBadBlocks ..

func (*Feechain) GetCurrentStakingErrorSink

func (fch *Feechain) GetCurrentStakingErrorSink() types.TransactionErrorReports

GetCurrentStakingErrorSink ..

func (*Feechain) GetCurrentTransactionErrorSink

func (fch *Feechain) GetCurrentTransactionErrorSink() types.TransactionErrorReports

GetCurrentTransactionErrorSink ..

func (*Feechain) GetCurrentUtilityMetrics

func (fch *Feechain) GetCurrentUtilityMetrics() (*network.UtilityMetric, error)

GetCurrentUtilityMetrics ..

func (*Feechain) GetDelegationLockingPeriodInEpoch

func (fch *Feechain) GetDelegationLockingPeriodInEpoch(epoch *big.Int) int

GetDelegationLockingPeriodInEpoch ...

func (*Feechain) GetDelegationsByDelegator

func (fch *Feechain) GetDelegationsByDelegator(
	delegator common.Address,
) ([]common.Address, []*staking.Delegation)

GetDelegationsByDelegator returns all delegation information of a delegator

func (*Feechain) GetDelegationsByDelegatorByBlock

func (fch *Feechain) GetDelegationsByDelegatorByBlock(
	delegator common.Address, block *types.Block,
) ([]common.Address, []*staking.Delegation)

GetDelegationsByDelegatorByBlock returns all delegation information of a delegator

func (*Feechain) GetDelegationsByValidator

func (fch *Feechain) GetDelegationsByValidator(validator common.Address) []*staking.Delegation

GetDelegationsByValidator returns all delegation information of a validator

func (*Feechain) GetDelegationsByValidatorAtBlock

func (fch *Feechain) GetDelegationsByValidatorAtBlock(
	validator common.Address, block *types.Block,
) []*staking.Delegation

GetDelegationsByValidatorAtBlock returns all delegation information of a validator at the given block

func (*Feechain) GetDetailedBlockSignerInfo

func (fch *Feechain) GetDetailedBlockSignerInfo(
	ctx context.Context, blk *types.Block,
) (*DetailedBlockSignerInfo, error)

GetDetailedBlockSignerInfo fetches the block signer information for any non-genesis block

func (*Feechain) GetEVM

func (fch *Feechain) GetEVM(ctx context.Context, msg core.Message, state *state.DB, header *block.Header) (*vm.EVM, error)

GetEVM returns a new EVM entity

func (*Feechain) GetElectedValidatorAddresses

func (fch *Feechain) GetElectedValidatorAddresses() []common.Address

GetElectedValidatorAddresses returns the address of elected validators for current epoch

func (fch *Feechain) GetLastCrossLinks() ([]*types.CrossLink, error)

GetLastCrossLinks ..

func (*Feechain) GetLatestChainHeaders

func (fch *Feechain) GetLatestChainHeaders() *block.HeaderPair

GetLatestChainHeaders ..

func (*Feechain) GetLeaderAddress

func (fch *Feechain) GetLeaderAddress(coinbaseAddr common.Address, epoch *big.Int) string

GetLeaderAddress returns the one address of the leader, given the coinbaseAddr. Note that the coinbaseAddr is overloaded with the BLS pub key hash in staking era.

func (*Feechain) GetLogs

func (fch *Feechain) GetLogs(ctx context.Context, blockHash common.Hash, isEth bool) ([][]*types.Log, error)

GetLogs ...

func (*Feechain) GetMedianRawStakeSnapshot

func (fch *Feechain) GetMedianRawStakeSnapshot() (
	*committee.CompletedEPoSRound, error,
)

GetMedianRawStakeSnapshot ..

func (*Feechain) GetNodeMetadata

func (fch *Feechain) GetNodeMetadata() commonRPC.NodeMetadata

GetNodeMetadata ..

func (*Feechain) GetPeerInfo

func (fch *Feechain) GetPeerInfo() commonRPC.NodePeerInfo

GetPeerInfo returns the peer info to the node, including blocked peer, connected peer, number of peers

func (*Feechain) GetPendingCXReceipts

func (fch *Feechain) GetPendingCXReceipts() []*types.CXReceiptsProof

GetPendingCXReceipts ..

func (*Feechain) GetPoolNonce

func (fch *Feechain) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)

GetPoolNonce ...

func (*Feechain) GetPoolStats

func (fch *Feechain) GetPoolStats() (pendingCount, queuedCount int)

GetPoolStats returns the number of pending and queued transactions

func (*Feechain) GetPoolTransaction

func (fch *Feechain) GetPoolTransaction(hash common.Hash) types.PoolTransaction

GetPoolTransaction ...

func (*Feechain) GetPoolTransactions

func (fch *Feechain) GetPoolTransactions() (types.PoolTransactions, error)

GetPoolTransactions returns pool transactions.

func (*Feechain) GetPreStakingBlockRewards

func (fch *Feechain) GetPreStakingBlockRewards(
	ctx context.Context, blk *types.Block,
) (PreStakingBlockRewards, error)

GetPreStakingBlockRewards for the given block number. Calculated rewards are done exactly like chain.AccumulateRewardsAndCountSigs.

func (*Feechain) GetReceipts

func (fch *Feechain) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)

GetReceipts ...

func (*Feechain) GetShardState

func (fch *Feechain) GetShardState() (*shard.State, error)

GetShardState ...

func (*Feechain) GetStakingTransactionsCount

func (fch *Feechain) GetStakingTransactionsCount(address, txType string) (uint64, error)

GetStakingTransactionsCount returns the number of staking transactions of address.

func (*Feechain) GetStakingTransactionsHistory

func (fch *Feechain) GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)

GetStakingTransactionsHistory returns list of staking transactions hashes of address.

func (*Feechain) GetSuperCommittees

func (fch *Feechain) GetSuperCommittees() (*quorum.Transition, error)

GetSuperCommittees ..

func (*Feechain) GetTotalStakingSnapshot

func (fch *Feechain) GetTotalStakingSnapshot() *big.Int

GetTotalStakingSnapshot ..

func (*Feechain) GetTransactionsCount

func (fch *Feechain) GetTransactionsCount(address, txType string) (uint64, error)

GetTransactionsCount returns the number of regular transactions of address.

func (*Feechain) GetTransactionsHistory

func (fch *Feechain) GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)

GetTransactionsHistory returns list of transactions hashes of address.

func (*Feechain) GetUndelegationPayouts

func (fch *Feechain) GetUndelegationPayouts(
	ctx context.Context, epoch *big.Int,
) (*UndelegationPayouts, error)

GetUndelegationPayouts returns the undelegation payouts for each delegator

Due to in-memory caching, it is possible to get undelegation payouts for a state / epoch that has been pruned but have it be lost (and unable to recompute) after the node restarts. This not a problem if a full (archival) DB is used.

func (*Feechain) GetValidatorInformation

func (fch *Feechain) GetValidatorInformation(
	addr common.Address, block *types.Block,
) (*staking.ValidatorRPCEnhanced, error)

GetValidatorInformation returns the information of validator

func (*Feechain) GetValidatorSelfDelegation

func (fch *Feechain) GetValidatorSelfDelegation(addr common.Address) *big.Int

GetValidatorSelfDelegation returns the amount of staking after applying all delegated stakes

func (*Feechain) GetValidators

func (fch *Feechain) GetValidators(epoch *big.Int) (*shard.Committee, error)

GetValidators returns validators for a particular epoch.

func (*Feechain) HeaderByHash

func (fch *Feechain) HeaderByHash(ctx context.Context, blockHash common.Hash) (*block.Header, error)

HeaderByHash ...

func (*Feechain) HeaderByNumber

func (fch *Feechain) HeaderByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*block.Header, error)

HeaderByNumber ...

func (*Feechain) IsCommitteeSelectionBlock

func (fch *Feechain) IsCommitteeSelectionBlock(header *block.Header) bool

IsCommitteeSelectionBlock checks if the given block is the committee selection block

func (*Feechain) IsLeader

func (fch *Feechain) IsLeader() bool

IsLeader exposes if node is currently leader

func (*Feechain) IsStakingEpoch

func (fch *Feechain) IsStakingEpoch(epoch *big.Int) bool

IsStakingEpoch ...

func (*Feechain) ProtocolVersion

func (fch *Feechain) ProtocolVersion() int

ProtocolVersion ...

func (*Feechain) ResendCx

func (fch *Feechain) ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)

ResendCx retrieve blockHash from txID and add blockHash to CxPool for resending Note that cross shard txn is only for regular txns, not for staking txns, so the input txn hash is expected to be regular txn hash

func (*Feechain) SendStakingTx

func (fch *Feechain) SendStakingTx(ctx context.Context, signedStakingTx *staking.StakingTransaction) error

SendStakingTx adds a staking transaction

func (*Feechain) SendTx

func (fch *Feechain) SendTx(ctx context.Context, signedTx *types.Transaction) error

SendTx ...

func (*Feechain) ServiceFilter

func (fch *Feechain) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)

ServiceFilter ...

func (*Feechain) SingleFlightForgetKey

func (fch *Feechain) SingleFlightForgetKey(key string)

SingleFlightForgetKey ...

func (*Feechain) SingleFlightRequest

func (fch *Feechain) SingleFlightRequest(
	key string,
	fn func() (interface{}, error),
) (interface{}, error)

SingleFlightRequest ..

func (*Feechain) StateAndHeaderByNumber

func (fch *Feechain) StateAndHeaderByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*state.DB, *block.Header, error)

StateAndHeaderByNumber ...

func (*Feechain) SubscribeChainEvent

func (fch *Feechain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription

SubscribeChainEvent subscribes chain event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SubscribeChainHeadEvent

func (fch *Feechain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription

SubscribeChainHeadEvent subcribes chain head event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SubscribeChainSideEvent

func (fch *Feechain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription

SubscribeChainSideEvent subcribes chain side event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SubscribeLogsEvent

func (fch *Feechain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription

SubscribeLogsEvent subcribes log event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SubscribeNewTxsEvent

func (fch *Feechain) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription

SubscribeNewTxsEvent subscribes new tx event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SubscribeRemovedLogsEvent

func (fch *Feechain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription

SubscribeRemovedLogsEvent subcribes removed logs event. TODO: this is not implemented or verified yet for feechain.

func (*Feechain) SuggestPrice

func (fch *Feechain) SuggestPrice(ctx context.Context) (*big.Int, error)

func (*Feechain) TraceBlock

func (fch *Feechain) TraceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*TxTraceResult, error)

TraceBlock configures a new tracer according to the provided configuration, and executes all the transactions contained within. The return value will be one item per transaction, dependent on the requested tracer.

func (*Feechain) TraceChain

func (fch *Feechain) TraceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error)

TraceChain configures a new tracer according to the provided configuration, and executes all the transactions contained within. The return value will be one item per transaction, dependent on the requested tracer.

func (*Feechain) TraceTx

func (fch *Feechain) TraceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.DB, config *TraceConfig) (interface{}, error)

TraceTx configures a new tracer according to the provided configuration, and executes the given message in the provided environment. The return value will be tracer dependent. NOTE: Only support default StructLogger tracer

type GasPriceConfig

type GasPriceConfig struct {
	Blocks     int
	Percentile int
	Default    *big.Int `toml:",omitempty"`
	MaxPrice   *big.Int `toml:",omitempty"`
}

type NodeAPI

type NodeAPI interface {
	AddPendingStakingTransaction(*staking.StakingTransaction) error
	AddPendingTransaction(newTx *types.Transaction) error
	Blockchain() *core.BlockChain
	Beaconchain() *core.BlockChain
	GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
	GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
	GetTransactionsCount(address, txType string) (uint64, error)
	GetStakingTransactionsCount(address, txType string) (uint64, error)
	IsCurrentlyLeader() bool
	IsOutOfSync(shardID uint32) bool
	SyncStatus(shardID uint32) (bool, uint64, uint64)
	SyncPeers() map[string]int
	ReportStakingErrorSink() types.TransactionErrorReports
	ReportPlainErrorSink() types.TransactionErrorReports
	PendingCXReceipts() []*types.CXReceiptsProof
	GetNodeBootTime() int64
	PeerConnectivity() (int, int, int)
	ListPeer(topic string) []peer.ID
	ListTopic() []string
	ListBlockedPeer() []peer.ID

	GetConsensusInternal() commonRPC.ConsensusInternal
	IsBackup() bool
	SetNodeBackupMode(isBackup bool) bool

	// debug API
	GetConsensusMode() string
	GetConsensusPhase() string
	GetConsensusViewChangingID() uint64
	GetConsensusCurViewID() uint64
	GetConfig() commonRPC.Config
	ShutDown()
	GetLastSigningPower() (float64, error)
}

NodeAPI is the list of functions from node used to call rpc apis.

type Oracle

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

Oracle recommends gas prices based on the content of recent blocks. Suitable for both light and full clients.

func NewOracle

func NewOracle(backend *Feechain, params GasPriceConfig) *Oracle

NewOracle returns a new gasprice oracle which can recommend suitable gasprice for newly created transaction.

func (*Oracle) SuggestPrice

func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error)

SuggestPrice returns a gasprice so that newly created transaction can have a very high chance to be included in the following blocks.

type OracleBackend

type OracleBackend interface {
	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*block.Header, error)
	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
	ChainConfig() *params.ChainConfig
}

OracleBackend includes all necessary background APIs for oracle.

type PreStakingBlockRewards

type PreStakingBlockRewards map[common.Address]*big.Int

PreStakingBlockRewards are the rewards for a block in the pre-staking era (epoch < staking epoch).

type StdTraceConfig

type StdTraceConfig struct {
	*vm.LogConfig
	Reexec *uint64
	TxHash common.Hash
}

StdTraceConfig holds extra parameters to standard-json trace functions.

type StructLogRes

type StructLogRes struct {
	Pc              uint64            `json:"pc"`
	Op              string            `json:"op"`
	CallerAddress   common.Address    `json:"callerAddress"`
	ContractAddress common.Address    `json:"contractAddress"`
	Gas             uint64            `json:"gas"`
	GasCost         uint64            `json:"gasCost"`
	Depth           int               `json:"depth"`
	Error           error             `json:"error,omitempty"`
	Stack           []string          `json:"stack,omitempty"`
	AfterStack      []string          `json:"afterStack,omitempty"`
	Memory          []string          `json:"memory,omitempty"`
	Storage         map[string]string `json:"storage,omitempty"`
	// contains filtered or unexported fields
}

StructLogRes stores a structured log emitted by the EVM while replaying a transaction in debug mode

func FormatLogs

func FormatLogs(logs []*vm.StructLog, conf *TraceConfig) []StructLogRes

FormatLogs formats EVM returned structured logs for json output

func (*StructLogRes) FormatAfterStack

func (r *StructLogRes) FormatAfterStack() []string

func (*StructLogRes) FormatMemory

func (r *StructLogRes) FormatMemory() []string

func (*StructLogRes) FormatStack

func (r *StructLogRes) FormatStack() []string

func (*StructLogRes) FormatStorage

func (r *StructLogRes) FormatStorage() map[string]string

func (*StructLogRes) GetOperatorEvent

func (r *StructLogRes) GetOperatorEvent(key string) string

type TraceConfig

type TraceConfig struct {
	*vm.LogConfig
	Tracer  *string
	Timeout *string
	Reexec  *uint64
}

TraceConfig holds extra parameters to trace functions.

type TxTraceResult

type TxTraceResult struct {
	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
}

TxTraceResult is the result of a single transaction trace.

type UndelegationPayouts

type UndelegationPayouts struct {
	Data map[common.Address]map[common.Address]*big.Int
}

UndelegationPayouts ..

func NewUndelegationPayouts

func NewUndelegationPayouts() *UndelegationPayouts

func (*UndelegationPayouts) SetPayoutByDelegatorAddrAndValidatorAddr

func (u *UndelegationPayouts) SetPayoutByDelegatorAddrAndValidatorAddr(
	delegator, validator common.Address, amount *big.Int,
)

Directories

Path Synopsis
Package tracers is a collection of JavaScript transaction tracers.
Package tracers is a collection of JavaScript transaction tracers.
internal/tracers
Package tracers contains the actual JavaScript tracer assets.
Package tracers contains the actual JavaScript tracer assets.

Jump to

Keyboard shortcuts

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