types

package
v0.0.0-...-5628e88 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2022 License: Apache-2.0 Imports: 32 Imported by: 2

Documentation

Index

Constants

View Source
const AccountStorageRootIndex = 2
View Source
const (
	ModuleName = "trusted ethereum"
)
View Source
const (
	TrustedEthereum string = "trusted-ethereum"
)

Variables

View Source
var (
	ErrInvalidChainID              = sdkerrors.Register(ModuleName, 2, "invalid chain-id")
	ErrInvalidHeaderHeight         = sdkerrors.Register(ModuleName, 3, "invalid header height")
	ErrInvalidHeader               = sdkerrors.Register(ModuleName, 4, "invalid header")
	ErrInvalidSequence             = sdkerrors.Register(ModuleName, 5, "invalid sequence")
	ErrInvalidSignatureAndData     = sdkerrors.Register(ModuleName, 6, "invalid signature and data")
	ErrSignatureVerificationFailed = sdkerrors.Register(ModuleName, 7, "signature verification failed")
	ErrInvalidProof                = sdkerrors.Register(ModuleName, 8, "invalid proof")
	ErrInvalidDataType             = sdkerrors.Register(ModuleName, 9, "invalid data type")
	ErrProcessedTimeNotFound       = sdkerrors.Register(ModuleName, 10, "processed time not found")
	ErrProcessedHeightNotFound     = sdkerrors.Register(ModuleName, 11, "processed height not found")
	ErrDelayPeriodNotPassed        = sdkerrors.Register(ModuleName, 12, "packet-specified delay period has not been reached")
)
View Source
var (
	ErrInvalidLengthTrustedEthereum        = fmt.Errorf("proto: negative length found during unmarshaling")
	ErrIntOverflowTrustedEthereum          = fmt.Errorf("proto: integer overflow")
	ErrUnexpectedEndOfGroupTrustedEthereum = fmt.Errorf("proto: unexpected end of group")
)

Functions

func ChannelCommitmentKey

func ChannelCommitmentKey(portId, channelId string) ([]byte, error)

func ChannelCommitmentSlot

func ChannelCommitmentSlot(portId, channelId string) ([]byte, error)

func ClientCommitmentKey

func ClientCommitmentKey(clientId string) ([]byte, error)

func ClientStateCommitmentSlot

func ClientStateCommitmentSlot(clientId string) ([]byte, error)

func ConnectionCommitmentKey

func ConnectionCommitmentKey(connectionId string) ([]byte, error)

func ConnectionCommitmentSlot

func ConnectionCommitmentSlot(connectionId string) ([]byte, error)

func ConsensusCommitmentKey

func ConsensusCommitmentKey(clientId string, height uint64) ([]byte, error)

func ConsensusStateCommitmentSlot

func ConsensusStateCommitmentSlot(clientId string, height uint64) ([]byte, error)

func HeaderSignBytes

func HeaderSignBytes(
	cdc codec.BinaryCodec,
	header *Header,
) ([]byte, error)

HeaderSignBytes returns the sign bytes for verification of misbehaviour.

func PacketAcknowledgementCommitmentKey

func PacketAcknowledgementCommitmentKey(portId, channelId string, sequence uint64) ([]byte, error)

func PacketAcknowledgementCommitmentSlot

func PacketAcknowledgementCommitmentSlot(portId, channelId string, sequence uint64) ([]byte, error)

func PacketCommitmentKey

func PacketCommitmentKey(portId, channelId string, sequence uint64) ([]byte, error)

func PacketCommitmentSlot

func PacketCommitmentSlot(portId, channelId string, sequence uint64) ([]byte, error)

func RegisterInterfaces

func RegisterInterfaces(registry codectypes.InterfaceRegistry)

RegisterInterfaces register the ibc channel submodule interfaces to protobuf Any.

func VerifyEthAccountProof

func VerifyEthAccountProof(proof [][]byte, stateRoot common.Hash, addressBytes []byte) ([]byte, error)

VerifyEthAccountProof verifies an Ethereum account proof against the StateRoot. It does not verify the storage proof(s).

func VerifyEthStorageProof

func VerifyEthStorageProof(proof [][]byte, storageHash common.Hash, key, value []byte) error

VerifyEthStorageProof verifies an Ethereum storage proof against the StateRoot. It does not verify the account proof against the Ethereum StateHash.

func VerifyProof

func VerifyProof(rootHash common.Hash, key []byte, value []byte, proof [][]byte) error

VerifyProof verifies that the path generated from key, following the nodes in proof leads to a leaf with value, where the hashes are correct up to the rootHash. WARNING: When the value is not found, `eth_getProof` will return "0x0" at the StorageProof `value` field. In order to verify the proof of non existence, you must set `value` to nil, *not* the RLP encoding of 0 or null (which would be 0x80).

func VerifySignature

func VerifySignature(pubKey cryptotypes.PubKey, signBytes []byte, signature []byte) error

VerifySignature verifies if the the provided public key generated the signature over the given data. Single signature public keys are supported. The signature data type must correspond to the public key type. An error is returned if signature verification fails.

Types

type ClientState

type ClientState struct {
	ChainId         string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
	IbcStoreAddress []byte `protobuf:"bytes,2,opt,name=ibc_store_address,json=ibcStoreAddress,proto3" json:"ibc_store_address,omitempty"`
	// Latest height the client was updated to
	LatestHeight types.Height `protobuf:"bytes,3,opt,name=latest_height,json=latestHeight,proto3" json:"latest_height" yaml:"latest_height"`
	// Block height when the client was frozen due to a misbehaviour
	FrozenHeight types.Height `protobuf:"bytes,4,opt,name=frozen_height,json=frozenHeight,proto3" json:"frozen_height" yaml:"frozen_height"`
}

func (ClientState) CheckHeaderAndUpdateState

func (cs ClientState) CheckHeaderAndUpdateState(
	ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore,
	header exported.Header,
) (exported.ClientState, exported.ConsensusState, error)

CheckHeaderAndUpdateState checks if the provided header is valid and updates the consensus state if appropriate. It returns an error if: - the header provided is not parseable to a Mock header

func (ClientState) CheckMisbehaviourAndUpdateState

func (cs ClientState) CheckMisbehaviourAndUpdateState(
	ctx sdk.Context,
	cdc codec.BinaryCodec,
	clientStore sdk.KVStore,
	misbehaviour exported.Misbehaviour,
) (exported.ClientState, error)

CheckMisbehaviourAndUpdateState determines whether or not two conflicting headers at the same height would have convinced the light client.

Misbehaviour sets frozen height to {0, 1} since it is only used as a boolean value (zero or non-zero).

func (ClientState) CheckSubstituteAndUpdateState

func (cs ClientState) CheckSubstituteAndUpdateState(
	ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore,
	_ sdk.KVStore, substituteClient exported.ClientState,
) (exported.ClientState, error)

func (ClientState) ClientType

func (cs ClientState) ClientType() string

ClientType is tendermint.

func (*ClientState) Descriptor

func (*ClientState) Descriptor() ([]byte, []int)

func (ClientState) ExportMetadata

func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata

ExportMetadata is a no-op since Trusted Ethereum does not store any metadata in client store

func (ClientState) GetChainID

func (cs ClientState) GetChainID() string

GetChainID returns the chain-id

func (ClientState) GetFrozenHeight

func (cs ClientState) GetFrozenHeight() exported.Height

GetFrozenHeight returns the frozen sequence of the client. Return exported.Height to satisfy interface Revision number is always 0 for a solo-machine

func (ClientState) GetLatestHeight

func (cs ClientState) GetLatestHeight() exported.Height

GetLatestHeight returns latest block height.

func (ClientState) GetProofSpecs

func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec

GetProofSpecs returns nil proof specs since client state verification uses signatures.

func (ClientState) Initialize

func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error

Initialize will check that initial consensus state is a Tendermint consensus state and will store ProcessedTime for initial consensus state as ctx.BlockTime()

func (*ClientState) Marshal

func (m *ClientState) Marshal() (dAtA []byte, err error)

func (*ClientState) MarshalTo

func (m *ClientState) MarshalTo(dAtA []byte) (int, error)

func (*ClientState) MarshalToSizedBuffer

func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error)

func (*ClientState) ProtoMessage

func (*ClientState) ProtoMessage()

func (*ClientState) Reset

func (m *ClientState) Reset()

func (*ClientState) Size

func (m *ClientState) Size() (n int)

func (ClientState) Status

func (cs ClientState) Status(
	ctx sdk.Context,
	clientStore sdk.KVStore,
	cdc codec.BinaryCodec,
) exported.Status

Status returns the status of the tendermint client. The client may be: - Active: FrozenHeight is zero and client is not expired - Frozen: Frozen Height is not zero - Expired: the latest consensus state timestamp + trusting period <= current time

A frozen client will become expired, so the Frozen status has higher precedence.

func (*ClientState) String

func (m *ClientState) String() string

func (*ClientState) Unmarshal

func (m *ClientState) Unmarshal(dAtA []byte) error

func (ClientState) Validate

func (cs ClientState) Validate() error

Validate performs a basic validation of the client state fields.

func (ClientState) VerifyChannelState

func (cs ClientState) VerifyChannelState(
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	prefix exported.Prefix,
	proof []byte,
	portID,
	channelID string,
	channel exported.ChannelI,
) error

VerifyChannelState verifies a proof of the channel state of the specified channel end, under the specified port, stored on the target machine.

func (ClientState) VerifyClientConsensusState

func (cs ClientState) VerifyClientConsensusState(
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	counterpartyClientIdentifier string,
	consensusHeight exported.Height,
	prefix exported.Prefix,
	proof []byte,
	consensusState exported.ConsensusState,
) error

VerifyClientConsensusState verifies a proof of the consensus state of the Tendermint client stored on the target machine.

func (ClientState) VerifyClientState

func (cs ClientState) VerifyClientState(
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	prefix exported.Prefix,
	counterpartyClientIdentifier string,
	proof []byte,
	clientState exported.ClientState,
) error

VerifyClientState verifies a proof of the client state of the running chain stored on the target machine

func (ClientState) VerifyConnectionState

func (cs ClientState) VerifyConnectionState(
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	prefix exported.Prefix,
	proof []byte,
	connectionID string,
	connectionEnd exported.ConnectionI,
) error

VerifyConnectionState verifies a proof of the connection state of the specified connection end stored on the target machine.

func (ClientState) VerifyNextSequenceRecv

func (cs ClientState) VerifyNextSequenceRecv(
	ctx sdk.Context,
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	delayTimePeriod uint64,
	delayBlockPeriod uint64,
	prefix exported.Prefix,
	proof []byte,
	portID,
	channelID string,
	nextSequenceRecv uint64,
) error

VerifyNextSequenceRecv verifies a proof of the next sequence number to be received of the specified channel at the specified port.

func (ClientState) VerifyPacketAcknowledgement

func (cs ClientState) VerifyPacketAcknowledgement(
	ctx sdk.Context,
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	delayTimePeriod uint64,
	delayBlockPeriod uint64,
	prefix exported.Prefix,
	proof []byte,
	portID,
	channelID string,
	sequence uint64,
	acknowledgement []byte,
) error

VerifyPacketAcknowledgement verifies a proof of an incoming packet acknowledgement at the specified port, specified channel, and specified sequence.

func (ClientState) VerifyPacketCommitment

func (cs ClientState) VerifyPacketCommitment(
	ctx sdk.Context,
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	delayTimePeriod uint64,
	delayBlockPeriod uint64,
	prefix exported.Prefix,
	proof []byte,
	portID,
	channelID string,
	sequence uint64,
	commitmentBytes []byte,
) error

VerifyPacketCommitment verifies a proof of an outgoing packet commitment at the specified port, specified channel, and specified sequence.

func (ClientState) VerifyPacketReceiptAbsence

func (cs ClientState) VerifyPacketReceiptAbsence(
	ctx sdk.Context,
	store sdk.KVStore,
	cdc codec.BinaryCodec,
	height exported.Height,
	delayTimePeriod uint64,
	delayBlockPeriod uint64,
	prefix exported.Prefix,
	proof []byte,
	portID,
	channelID string,
	sequence uint64,
) error

VerifyPacketReceiptAbsence verifies a proof of the absence of an incoming packet receipt at the specified port, specified channel, and specified sequence.

func (ClientState) VerifyUpgradeAndUpdateState

VerifyUpgradeAndUpdateState returns an error since Multisig client does not support upgrades

func (*ClientState) XXX_DiscardUnknown

func (m *ClientState) XXX_DiscardUnknown()

func (*ClientState) XXX_Marshal

func (m *ClientState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*ClientState) XXX_Merge

func (m *ClientState) XXX_Merge(src proto.Message)

func (*ClientState) XXX_Size

func (m *ClientState) XXX_Size() int

func (*ClientState) XXX_Unmarshal

func (m *ClientState) XXX_Unmarshal(b []byte) error

func (ClientState) ZeroCustomFields

func (cs ClientState) ZeroCustomFields() exported.ClientState

ZeroCustomFields returns a ClientState that is a copy of the current ClientState with all client customizable fields zeroed out

type ConsensusState

type ConsensusState struct {
	// timestamp that corresponds to the block height in which the ConsensusState
	// was stored.
	Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
	// storage root for ibc_store_address
	Root types1.MerkleRoot `protobuf:"bytes,2,opt,name=root,proto3" json:"root"`
	// public key of the trusted submitter
	PublicKey *types2.Any `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty" yaml:"public_key"`
	// diversifier allows the same public key to be re-used across different
	// clients (potentially on different chains) without being considered
	// misbehaviour.
	Diversifier string `protobuf:"bytes,4,opt,name=diversifier,proto3" json:"diversifier,omitempty"`
}

func GetConsensusState

func GetConsensusState(store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (*ConsensusState, error)

GetConsensusState retrieves the consensus state from the client prefixed store. An error is returned if the consensus state does not exist.

func (ConsensusState) ClientType

func (ConsensusState) ClientType() string

ClientType returns TrustedEthereum

func (*ConsensusState) Descriptor

func (*ConsensusState) Descriptor() ([]byte, []int)

func (ConsensusState) GetPubKey

func (cs ConsensusState) GetPubKey() (cryptotypes.PubKey, error)

GetPubKey unmarshals the public key into a cryptotypes.PubKey type. An error is returned if the public key is nil or the cached value is not a PubKey.

func (ConsensusState) GetRoot

func (cs ConsensusState) GetRoot() exported.Root

GetRoot returns the commitment Root for the specific

func (ConsensusState) GetTimestamp

func (cs ConsensusState) GetTimestamp() uint64

GetTimestamp returns zero.

func (*ConsensusState) Marshal

func (m *ConsensusState) Marshal() (dAtA []byte, err error)

func (*ConsensusState) MarshalTo

func (m *ConsensusState) MarshalTo(dAtA []byte) (int, error)

func (*ConsensusState) MarshalToSizedBuffer

func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error)

func (ConsensusState) MustGetPubKey

func (cs ConsensusState) MustGetPubKey() cryptotypes.PubKey

func (*ConsensusState) ProtoMessage

func (*ConsensusState) ProtoMessage()

func (*ConsensusState) Reset

func (m *ConsensusState) Reset()

func (*ConsensusState) Size

func (m *ConsensusState) Size() (n int)

func (*ConsensusState) String

func (m *ConsensusState) String() string

func (*ConsensusState) Unmarshal

func (m *ConsensusState) Unmarshal(dAtA []byte) error

func (ConsensusState) UnpackInterfaces

func (cs ConsensusState) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error

UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method

func (ConsensusState) ValidateBasic

func (cs ConsensusState) ValidateBasic() error

ValidateBasic defines basic validation for the Multisig consensus state.

func (*ConsensusState) XXX_DiscardUnknown

func (m *ConsensusState) XXX_DiscardUnknown()

func (*ConsensusState) XXX_Marshal

func (m *ConsensusState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*ConsensusState) XXX_Merge

func (m *ConsensusState) XXX_Merge(src proto.Message)

func (*ConsensusState) XXX_Size

func (m *ConsensusState) XXX_Size() int

func (*ConsensusState) XXX_Unmarshal

func (m *ConsensusState) XXX_Unmarshal(b []byte) error
type Header struct {
	// height to update multisig public key at
	Height    types.Height `protobuf:"bytes,1,opt,name=height,proto3" json:"height"`
	StateRoot []byte       `protobuf:"bytes,2,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
	Timestamp uint64       `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
	// account_proof follows the proof format of IBFT2.0 client
	AccountProof   []byte      `protobuf:"bytes,4,opt,name=account_proof,json=accountProof,proto3" json:"account_proof,omitempty"`
	Signature      []byte      `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"`
	NewPublicKey   *types2.Any `protobuf:"bytes,6,opt,name=new_public_key,json=newPublicKey,proto3" json:"new_public_key,omitempty" yaml:"new_public_key"`
	NewDiversifier string      `` /* 126-byte string literal not displayed */
}

Header defines a multisig consensus header

func (Header) ClientType

func (Header) ClientType() string

ClientType defines that the Header is a Multisig.

func (*Header) Descriptor

func (*Header) Descriptor() ([]byte, []int)

func (Header) GetHeight

func (h Header) GetHeight() exported.Height

GetHeight returns the current height. It returns 0 if the ethereum header is nil.

Return clientexported.Height to satisfy interface Revision number is always 0 for a trusted ethereum

func (Header) GetPubKey

func (h Header) GetPubKey() (cryptotypes.PubKey, error)

GetPubKey unmarshals the new public key into a cryptotypes.PubKey type. An error is returned if the new public key is nil or the cached value is not a PubKey.

func (Header) GetTimestamp

func (h Header) GetTimestamp() uint64

GetTimestamp returns the current block timestamp. It returns a zero time if the ethereum header is nil.

func (*Header) Marshal

func (m *Header) Marshal() (dAtA []byte, err error)

func (*Header) MarshalTo

func (m *Header) MarshalTo(dAtA []byte) (int, error)

func (*Header) MarshalToSizedBuffer

func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error)

func (*Header) ProtoMessage

func (*Header) ProtoMessage()

func (*Header) Reset

func (m *Header) Reset()

func (*Header) Size

func (m *Header) Size() (n int)

func (*Header) String

func (m *Header) String() string

func (*Header) Unmarshal

func (m *Header) Unmarshal(dAtA []byte) error

func (Header) UnpackInterfaces

func (h Header) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error

UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method

func (Header) ValidateBasic

func (h Header) ValidateBasic() error

ValidateBasic ensures that the sequence, signature and public key have all been initialized.

func (*Header) XXX_DiscardUnknown

func (m *Header) XXX_DiscardUnknown()

func (*Header) XXX_Marshal

func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*Header) XXX_Merge

func (m *Header) XXX_Merge(src proto.Message)

func (*Header) XXX_Size

func (m *Header) XXX_Size() int

func (*Header) XXX_Unmarshal

func (m *Header) XXX_Unmarshal(b []byte) error

type MemDB

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

MemDB is an ethdb.KeyValueReader implementation which is not thread safe and assumes that all keys are common.Hash.

func NewMemDB

func NewMemDB() *MemDB

NewMemDB creates a new empty MemDB

func (*MemDB) Get

func (m *MemDB) Get(key []byte) ([]byte, error)

Get returns the value of the key, or nil if it's not found

func (*MemDB) Has

func (m *MemDB) Has(key []byte) (bool, error)

Has returns true if the MemBD contains the key

func (*MemDB) Put

func (m *MemDB) Put(key []byte, value []byte)

Put sets or updates the value at key

type Misbehaviour

type Misbehaviour struct {
	ClientId string  `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"`
	Header1  *Header `protobuf:"bytes,2,opt,name=header_1,json=header1,proto3" json:"header_1,omitempty" yaml:"header_1"`
	Header2  *Header `protobuf:"bytes,3,opt,name=header_2,json=header2,proto3" json:"header_2,omitempty" yaml:"header_2"`
}

Misbehaviour defines misbehaviour for a multisig which consists of a sequence and two signatures over different messages at that sequence.

func (Misbehaviour) ClientType

func (misbehaviour Misbehaviour) ClientType() string

ClientType is a Multisig light client.

func (*Misbehaviour) Descriptor

func (*Misbehaviour) Descriptor() ([]byte, []int)

func (Misbehaviour) GetClientID

func (misbehaviour Misbehaviour) GetClientID() string

GetClientID returns the ID of the client that committed a misbehaviour.

func (Misbehaviour) GetHeight

func (misbehaviour Misbehaviour) GetHeight() exported.Height

GetHeight returns the sequence at which misbehaviour occurred. Return exported.Height to satisfy interface

func (*Misbehaviour) Marshal

func (m *Misbehaviour) Marshal() (dAtA []byte, err error)

func (*Misbehaviour) MarshalTo

func (m *Misbehaviour) MarshalTo(dAtA []byte) (int, error)

func (*Misbehaviour) MarshalToSizedBuffer

func (m *Misbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, error)

func (*Misbehaviour) ProtoMessage

func (*Misbehaviour) ProtoMessage()

func (*Misbehaviour) Reset

func (m *Misbehaviour) Reset()

func (*Misbehaviour) Size

func (m *Misbehaviour) Size() (n int)

func (*Misbehaviour) String

func (m *Misbehaviour) String() string

func (Misbehaviour) Type

func (misbehaviour Misbehaviour) Type() string

Type implements Evidence interface.

func (*Misbehaviour) Unmarshal

func (m *Misbehaviour) Unmarshal(dAtA []byte) error

func (Misbehaviour) ValidateBasic

func (misbehaviour Misbehaviour) ValidateBasic() error

ValidateBasic implements Evidence interface.

func (*Misbehaviour) XXX_DiscardUnknown

func (m *Misbehaviour) XXX_DiscardUnknown()

func (*Misbehaviour) XXX_Marshal

func (m *Misbehaviour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*Misbehaviour) XXX_Merge

func (m *Misbehaviour) XXX_Merge(src proto.Message)

func (*Misbehaviour) XXX_Size

func (m *Misbehaviour) XXX_Size() int

func (*Misbehaviour) XXX_Unmarshal

func (m *Misbehaviour) XXX_Unmarshal(b []byte) error

Jump to

Keyboard shortcuts

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