localstatequery

package
v0.106.2 Latest Latest
Warning

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

Go to latest
Published: Dec 31, 2024 License: Apache-2.0 Imports: 10 Imported by: 3

Documentation

Overview

Package localstatequery implements the Ouroboros local-state-query protocol

Index

Constants

View Source
const (
	ProtocolName        = "local-state-query"
	ProtocolId   uint16 = 7
)

Protocol identifiers

View Source
const (
	MessageTypeAcquire               = 0
	MessageTypeAcquired              = 1
	MessageTypeFailure               = 2
	MessageTypeQuery                 = 3
	MessageTypeResult                = 4
	MessageTypeRelease               = 5
	MessageTypeReacquire             = 6
	MessageTypeDone                  = 7
	MessageTypeAcquireVolatileTip    = 8
	MessageTypeReacquireVolatileTip  = 9
	MessageTypeAcquireImmutableTip   = 10
	MessageTypeReacquireImmutableTip = 11
)

Message types

View Source
const (
	AcquireFailurePointTooOld     = 0
	AcquireFailurePointNotOnChain = 1
)

Acquire failure reasons

View Source
const (
	QueryTypeBlock        = 0
	QueryTypeSystemStart  = 1
	QueryTypeChainBlockNo = 2
	QueryTypeChainPoint   = 3

	// Block query sub-types
	QueryTypeShelley  = 0
	QueryTypeHardFork = 2

	// Hard fork query sub-types
	QueryTypeHardForkEraHistory = 0
	QueryTypeHardForkCurrentEra = 1

	// Shelley query sub-types
	QueryTypeShelleyLedgerTip                           = 0
	QueryTypeShelleyEpochNo                             = 1
	QueryTypeShelleyNonMyopicMemberRewards              = 2
	QueryTypeShelleyCurrentProtocolParams               = 3
	QueryTypeShelleyProposedProtocolParamsUpdates       = 4
	QueryTypeShelleyStakeDistribution                   = 5
	QueryTypeShelleyUtxoByAddress                       = 6
	QueryTypeShelleyUtxoWhole                           = 7
	QueryTypeShelleyDebugEpochState                     = 8
	QueryTypeShelleyCbor                                = 9
	QueryTypeShelleyFilteredDelegationAndRewardAccounts = 10
	QueryTypeShelleyGenesisConfig                       = 11
	QueryTypeShelleyDebugNewEpochState                  = 12
	QueryTypeShelleyDebugChainDepState                  = 13
	QueryTypeShelleyRewardProvenance                    = 14
	QueryTypeShelleyUtxoByTxin                          = 15
	QueryTypeShelleyStakePools                          = 16
	QueryTypeShelleyStakePoolParams                     = 17
	QueryTypeShelleyRewardInfoPools                     = 18
	QueryTypeShelleyPoolState                           = 19
	QueryTypeShelleyStakeSnapshots                      = 20
	QueryTypeShelleyPoolDistr                           = 21
)

Query types

Variables

View Source
var ErrAcquireFailurePointNotOnChain = errors.New("acquire failure: point not on chain")

ErrAcquireFailurePointNotOnChain indicates a failure to acquire a point due to it not being present on the chain

View Source
var ErrAcquireFailurePointTooOld = errors.New("acquire failure: point too old")

ErrAcquireFailurePointTooOld indicates a failure to acquire a point due to it being too old

View Source
var StateMap = protocol.StateMap{
	// contains filtered or unexported fields
}

LocalStateQuery protocol state machine

Functions

func NewMsgFromCbor

func NewMsgFromCbor(msgType uint, data []byte) (protocol.Message, error)

NewMsgFromCbor parses a LocalStateQuery message from CBOR

Types

type AcquireFunc

type AcquireFunc func(CallbackContext, AcquireTarget, bool) error

Callback function types

type AcquireImmutableTip added in v0.106.0

type AcquireImmutableTip struct{}

type AcquireSpecificPoint added in v0.106.0

type AcquireSpecificPoint struct {
	Point common.Point
}

type AcquireTarget added in v0.106.0

type AcquireTarget interface {
	// contains filtered or unexported methods
}

Acquire target types

type AcquireVolatileTip added in v0.106.0

type AcquireVolatileTip struct{}

type BlockQuery added in v0.106.0

type BlockQuery struct {
	Query any
}

func (*BlockQuery) MarshalCBOR added in v0.106.0

func (q *BlockQuery) MarshalCBOR() ([]byte, error)

func (*BlockQuery) UnmarshalCBOR added in v0.106.0

func (q *BlockQuery) UnmarshalCBOR(data []byte) error

type CallbackContext added in v0.78.0

type CallbackContext struct {
	ConnectionId connection.ConnectionId
	Client       *Client
	Server       *Server
}

Callback context

type ChainBlockNoQuery added in v0.106.0

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

type ChainPointQuery added in v0.106.0

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

type Client

type Client struct {
	*protocol.Protocol
	// contains filtered or unexported fields
}

Client implements the LocalStateQuery client

func NewClient

func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client

NewClient returns a new LocalStateQuery client object

func (*Client) Acquire

func (c *Client) Acquire(point *common.Point) error

Acquire starts the acquire process for the specified chain point

func (*Client) AcquireImmutableTip added in v0.106.0

func (c *Client) AcquireImmutableTip() error

func (*Client) AcquireVolatileTip added in v0.106.0

func (c *Client) AcquireVolatileTip() error

func (*Client) DebugChainDepState

func (c *Client) DebugChainDepState() (*DebugChainDepStateResult, error)

TODO

func (*Client) DebugEpochState

func (c *Client) DebugEpochState() (*DebugEpochStateResult, error)

TODO

func (*Client) DebugNewEpochState

func (c *Client) DebugNewEpochState() (*DebugNewEpochStateResult, error)

TODO

func (*Client) GetChainBlockNo

func (c *Client) GetChainBlockNo() (int64, error)

GetChainBlockNo returns the latest block number

func (*Client) GetChainPoint

func (c *Client) GetChainPoint() (*common.Point, error)

GetChainPoint returns the current chain tip

func (*Client) GetCurrentEra

func (c *Client) GetCurrentEra() (int, error)

GetCurrentEra returns the current era ID

func (*Client) GetCurrentProtocolParams

func (c *Client) GetCurrentProtocolParams() (ledgercommon.ProtocolParameters, error)

GetCurrentProtocolParams returns the set of protocol params that are currently in effect

func (*Client) GetEpochNo

func (c *Client) GetEpochNo() (int, error)

GetEpochNo returns the current epoch number

func (*Client) GetEraHistory

func (c *Client) GetEraHistory() ([]EraHistoryResult, error)

GetEraHistory returns the era history

func (*Client) GetFilteredDelegationsAndRewardAccounts

func (c *Client) GetFilteredDelegationsAndRewardAccounts(
	creds []interface{},
) (*FilteredDelegationsAndRewardAccountsResult, error)

TODO

query [10 #6.258([ *rwdr ])]

func (*Client) GetGenesisConfig

func (c *Client) GetGenesisConfig() (*GenesisConfigResult, error)

func (*Client) GetNonMyopicMemberRewards

func (c *Client) GetNonMyopicMemberRewards() (*NonMyopicMemberRewardsResult, error)

TODO

query [2 #6.258([*[0 int]]) int is the stake the user intends to delegate, the array must be sorted

func (*Client) GetPoolDistr

func (c *Client) GetPoolDistr(poolIds []interface{}) (*PoolDistrResult, error)

TODO

func (*Client) GetPoolState

func (c *Client) GetPoolState(poolIds []interface{}) (*PoolStateResult, error)

TODO

func (*Client) GetProposedProtocolParamsUpdates

func (c *Client) GetProposedProtocolParamsUpdates() (*ProposedProtocolParamsUpdatesResult, error)

GetProposedProtocolParamsUpdates returns the set of proposed protocol params updates

func (*Client) GetRewardInfoPools

func (c *Client) GetRewardInfoPools() (*RewardInfoPoolsResult, error)

TODO

func (*Client) GetRewardProvenance

func (c *Client) GetRewardProvenance() (*RewardProvenanceResult, error)

func (*Client) GetStakeDistribution

func (c *Client) GetStakeDistribution() (*StakeDistributionResult, error)

GetStakeDistribution returns the stake distribution

func (*Client) GetStakePoolParams

func (c *Client) GetStakePoolParams(
	poolIds []ledger.PoolId,
) (*StakePoolParamsResult, error)

func (*Client) GetStakePools

func (c *Client) GetStakePools() (*StakePoolsResult, error)

func (*Client) GetStakeSnapshots

func (c *Client) GetStakeSnapshots(
	poolId interface{},
) (*StakeSnapshotsResult, error)

TODO

func (*Client) GetSystemStart

func (c *Client) GetSystemStart() (*SystemStartResult, error)

GetSystemStart returns the SystemStart value

func (*Client) GetUTxOByAddress

func (c *Client) GetUTxOByAddress(
	addrs []ledger.Address,
) (*UTxOByAddressResult, error)

GetUTxOByAddress returns the UTxOs for a given list of ledger.Address structs

func (*Client) GetUTxOByTxIn

func (c *Client) GetUTxOByTxIn(
	txIns []ledger.TransactionInput,
) (*UTxOByTxInResult, error)

func (*Client) GetUTxOWhole

func (c *Client) GetUTxOWhole() (*UTxOWholeResult, error)

GetUTxOWhole returns the current UTxO set

func (*Client) Release

func (c *Client) Release() error

Release releases the previously acquired chain point

func (*Client) Start added in v0.73.3

func (c *Client) Start()

type Config

type Config struct {
	AcquireFunc    AcquireFunc
	QueryFunc      QueryFunc
	ReleaseFunc    ReleaseFunc
	AcquireTimeout time.Duration
	QueryTimeout   time.Duration
}

Config is used to configure the LocalStateQuery protocol instance

func NewConfig

func NewConfig(options ...LocalStateQueryOptionFunc) Config

NewConfig returns a new LocalStateQuery config object with the provided options

type DebugChainDepStateResult

type DebugChainDepStateResult interface{}

TODO

type DebugEpochStateResult

type DebugEpochStateResult interface{}

TODO

type DebugNewEpochStateResult

type DebugNewEpochStateResult interface{}

TODO

type EraHistoryResult

type EraHistoryResult struct {
	Begin  eraHistoryResultBeginEnd
	End    eraHistoryResultBeginEnd
	Params eraHistoryResultParams
	// contains filtered or unexported fields
}

type FilteredDelegationsAndRewardAccountsResult

type FilteredDelegationsAndRewardAccountsResult interface{}

TODO

rwdr [flag bytestring] bytestring is the keyhash of the staking vkey flag 0/1 0=keyhash 1=scripthash result [[ delegation rewards] ] delegation { * rwdr => poolid } poolid is a bytestring rewards { * rwdr => int } It seems to be a requirement to sort the reward addresses on the query. Scripthash addresses come first, then within a group the bytestring being a network order integer sort ascending.

type GenesisConfigResult

type GenesisConfigResult struct {
	Start             SystemStartResult
	NetworkMagic      int
	NetworkId         uint8
	ActiveSlotsCoeff  []interface{}
	SecurityParam     int
	EpochLength       int
	SlotsPerKESPeriod int
	MaxKESEvolutions  int
	SlotLength        int
	UpdateQuorum      int
	MaxLovelaceSupply int64
	ProtocolParams    struct {
		MinFeeA               int
		MinFeeB               int
		MaxBlockBodySize      int
		MaxTxSize             int
		MaxBlockHeaderSize    int
		KeyDeposit            int
		PoolDeposit           int
		EMax                  int
		NOpt                  int
		A0                    []int
		Rho                   []int
		Tau                   []int
		DecentralizationParam []int
		ExtraEntropy          interface{}
		ProtocolVersionMajor  int
		ProtocolVersionMinor  int
		MinUTxOValue          int
		MinPoolCost           int
		// contains filtered or unexported fields
	}
	// This value contains maps with bytestring keys, which we can't parse yet
	GenDelegs cbor.RawMessage
	Unknown1  interface{}
	Unknown2  interface{}
	// contains filtered or unexported fields
}

type HardForkCurrentEraQuery added in v0.106.0

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

type HardForkEraHistoryQuery added in v0.106.0

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

type HardForkQuery added in v0.106.0

type HardForkQuery struct {
	Query any
}

func (*HardForkQuery) MarshalCBOR added in v0.106.0

func (q *HardForkQuery) MarshalCBOR() ([]byte, error)

func (*HardForkQuery) UnmarshalCBOR added in v0.106.0

func (q *HardForkQuery) UnmarshalCBOR(data []byte) error

type LocalStateQuery

type LocalStateQuery struct {
	Client *Client
	Server *Server
}

LocalStateQuery is a wrapper object that holds the client and server instances

func New

func New(protoOptions protocol.ProtocolOptions, cfg *Config) *LocalStateQuery

New returns a new LocalStateQuery object

type LocalStateQueryOptionFunc

type LocalStateQueryOptionFunc func(*Config)

LocalStateQueryOptionFunc represents a function used to modify the LocalStateQuery protocol config

func WithAcquireFunc

func WithAcquireFunc(acquireFunc AcquireFunc) LocalStateQueryOptionFunc

WithAcquireFunc specifies the Acquire callback function when acting as a server

func WithAcquireTimeout

func WithAcquireTimeout(timeout time.Duration) LocalStateQueryOptionFunc

WithAcquireTimeout specifies the timeout for the Acquire operation when acting as a client

func WithQueryFunc

func WithQueryFunc(queryFunc QueryFunc) LocalStateQueryOptionFunc

WithQueryFunc specifies the Query callback function when acting as a server

func WithQueryTimeout

func WithQueryTimeout(timeout time.Duration) LocalStateQueryOptionFunc

WithQueryTimeout specifies the timeout for the Query operation when acting as a client

func WithReleaseFunc

func WithReleaseFunc(releaseFunc ReleaseFunc) LocalStateQueryOptionFunc

WithReleaseFunc specifies the Release callback function when acting as a server

type MsgAcquire

type MsgAcquire struct {
	protocol.MessageBase
	Point common.Point
}

func NewMsgAcquire

func NewMsgAcquire(point common.Point) *MsgAcquire

type MsgAcquireImmutableTip added in v0.106.0

type MsgAcquireImmutableTip struct {
	protocol.MessageBase
}

func NewMsgAcquireImmutableTip added in v0.106.0

func NewMsgAcquireImmutableTip() *MsgAcquireImmutableTip

type MsgAcquireVolatileTip added in v0.106.0

type MsgAcquireVolatileTip struct {
	protocol.MessageBase
}

func NewMsgAcquireVolatileTip added in v0.106.0

func NewMsgAcquireVolatileTip() *MsgAcquireVolatileTip

type MsgAcquired

type MsgAcquired struct {
	protocol.MessageBase
}

func NewMsgAcquired

func NewMsgAcquired() *MsgAcquired

type MsgDone

type MsgDone struct {
	protocol.MessageBase
}

func NewMsgDone

func NewMsgDone() *MsgDone

type MsgFailure

type MsgFailure struct {
	protocol.MessageBase
	Failure uint8
}

func NewMsgFailure

func NewMsgFailure(failure uint8) *MsgFailure

type MsgQuery

type MsgQuery struct {
	protocol.MessageBase
	Query QueryWrapper
}

func NewMsgQuery

func NewMsgQuery(query interface{}) *MsgQuery

type MsgReAcquire

type MsgReAcquire struct {
	protocol.MessageBase
	Point common.Point
}

func NewMsgReAcquire

func NewMsgReAcquire(point common.Point) *MsgReAcquire

type MsgReAcquireImmutableTip added in v0.106.0

type MsgReAcquireImmutableTip struct {
	protocol.MessageBase
}

func NewMsgReAcquireImmutableTip added in v0.106.0

func NewMsgReAcquireImmutableTip() *MsgReAcquireImmutableTip

type MsgReAcquireVolatileTip added in v0.106.0

type MsgReAcquireVolatileTip struct {
	protocol.MessageBase
}

func NewMsgReAcquireVolatileTip added in v0.106.0

func NewMsgReAcquireVolatileTip() *MsgReAcquireVolatileTip

type MsgRelease

type MsgRelease struct {
	protocol.MessageBase
}

func NewMsgRelease

func NewMsgRelease() *MsgRelease

type MsgResult

type MsgResult struct {
	protocol.MessageBase
	Result cbor.RawMessage
}

func NewMsgResult

func NewMsgResult(resultCbor []byte) *MsgResult

type NonMyopicMemberRewardsResult

type NonMyopicMemberRewardsResult interface{}

TODO

result [{ *[0 int] => non_myopic_rewards }] for each stake display reward non_myopic_rewards { *poolid => int } int is the amount of lovelaces each pool would reward

type PoolDistrResult

type PoolDistrResult interface{}

TODO

type PoolStateResult

type PoolStateResult interface{}

TODO

type ProposedProtocolParamsUpdatesResult

type ProposedProtocolParamsUpdatesResult interface{}

TODO

type QueryFunc

type QueryFunc func(CallbackContext, QueryWrapper) (any, error)

type QueryWrapper added in v0.106.0

type QueryWrapper struct {
	cbor.DecodeStoreCbor
	Query any
}

QueryWrapper is used for decoding a query from CBOR

func (*QueryWrapper) MarshalCBOR added in v0.106.0

func (q *QueryWrapper) MarshalCBOR() ([]byte, error)

func (*QueryWrapper) UnmarshalCBOR added in v0.106.0

func (q *QueryWrapper) UnmarshalCBOR(data []byte) error

type ReleaseFunc

type ReleaseFunc func(CallbackContext) error

type RewardInfoPoolsResult

type RewardInfoPoolsResult interface{}

TODO

type RewardProvenanceResult

type RewardProvenanceResult interface{}

TODO

result [ *Element ] Expanded in order on the next rows. Element CDDL Comment epochLength poolMints { *poolid => block-count } maxLovelaceSupply NA NA NA ?circulatingsupply? total-blocks ?decentralization? [num den] ?available block entries success-rate [num den] NA NA ??treasuryCut activeStakeGo nil nil

type Server

type Server struct {
	*protocol.Protocol
	// contains filtered or unexported fields
}

Server implements the LocalStateQuery server

func NewServer

func NewServer(protoOptions protocol.ProtocolOptions, cfg *Config) *Server

NewServer returns a new LocalStateQuery server object

type ShelleyCborQuery added in v0.106.0

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

type ShelleyCurrentProtocolParamsQuery added in v0.106.0

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

type ShelleyDebugChainDepStateQuery added in v0.106.0

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

type ShelleyDebugEpochStateQuery added in v0.106.0

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

type ShelleyDebugNewEpochStateQuery added in v0.106.0

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

type ShelleyEpochNoQuery added in v0.106.0

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

type ShelleyFilteredDelegationAndRewardAccountsQuery added in v0.106.0

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

type ShelleyGenesisConfigQuery added in v0.106.0

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

type ShelleyLedgerTipQuery added in v0.106.0

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

type ShelleyNonMyopicMemberRewardsQuery added in v0.106.0

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

type ShelleyPoolDistrQuery added in v0.106.0

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

type ShelleyPoolStateQuery added in v0.106.0

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

type ShelleyProposedProtocolParamsUpdatesQuery added in v0.106.0

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

type ShelleyQuery added in v0.106.0

type ShelleyQuery struct {
	Era   uint
	Query any
}

func (*ShelleyQuery) MarshalCBOR added in v0.106.0

func (q *ShelleyQuery) MarshalCBOR() ([]byte, error)

func (*ShelleyQuery) UnmarshalCBOR added in v0.106.0

func (q *ShelleyQuery) UnmarshalCBOR(data []byte) error

type ShelleyRewardInfoPoolsQuery added in v0.106.0

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

type ShelleyRewardProvenanceQuery added in v0.106.0

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

type ShelleyStakeDistributionQuery added in v0.106.0

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

type ShelleyStakePoolParamsQuery added in v0.106.0

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

type ShelleyStakePoolsQuery added in v0.106.0

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

type ShelleyStakeSnapshotsQuery added in v0.106.0

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

type ShelleyUtxoByAddressQuery added in v0.106.0

type ShelleyUtxoByAddressQuery struct {
	cbor.StructAsArray
	Type  int
	Addrs []ledger.Address
}

type ShelleyUtxoByTxinQuery added in v0.106.0

type ShelleyUtxoByTxinQuery struct {
	cbor.StructAsArray
	Type  int
	TxIns []ledger.ShelleyTransactionInput
}

type ShelleyUtxoWholeQuery added in v0.106.0

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

type StakeDistributionResult

type StakeDistributionResult struct {
	cbor.StructAsArray
	Results map[ledger.PoolId]struct {
		cbor.StructAsArray
		StakeFraction *cbor.Rat
		VrfHash       ledger.Blake2b256
	}
}

type StakePoolParamsResult

type StakePoolParamsResult struct {
	cbor.StructAsArray
	Results map[ledger.PoolId]struct {
		cbor.StructAsArray
		Operator      ledger.Blake2b224
		VrfKeyHash    ledger.Blake2b256
		Pledge        uint
		FixedCost     uint
		Margin        *cbor.Rat
		RewardAccount ledger.Address
		PoolOwners    []ledger.Blake2b224
		Relays        []ledger.PoolRelay
		PoolMetadata  *struct {
			cbor.StructAsArray
			Url          string
			MetadataHash ledger.Blake2b256
		}
	}
}

type StakePoolsResult

type StakePoolsResult struct {
	cbor.StructAsArray
	Results []ledger.PoolId
}

type StakeSnapshotsResult

type StakeSnapshotsResult interface{}

TODO

type SystemStartQuery added in v0.106.0

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

type SystemStartResult

type SystemStartResult struct {
	Year        int
	Day         int
	Picoseconds uint64
	// contains filtered or unexported fields
}

type UTxOByAddressResult

type UTxOByAddressResult struct {
	cbor.StructAsArray
	Results map[UtxoId]ledger.BabbageTransactionOutput
}

type UTxOByTxInResult

type UTxOByTxInResult struct {
	cbor.StructAsArray
	Results map[UtxoId]ledger.BabbageTransactionOutput
}

type UTxOWholeResult

type UTxOWholeResult interface{}

TODO

result [{* utxo => value }]

type UtxoId added in v0.77.0

type UtxoId struct {
	cbor.StructAsArray
	Hash      ledger.Blake2b256
	Idx       int
	DatumHash ledger.Blake2b256
}

func (*UtxoId) MarshalCBOR added in v0.106.1

func (u *UtxoId) MarshalCBOR() ([]byte, error)

func (*UtxoId) UnmarshalCBOR added in v0.77.0

func (u *UtxoId) UnmarshalCBOR(data []byte) error

Jump to

Keyboard shortcuts

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