121 lines
3.5 KiB
Nim
121 lines
3.5 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
# http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed except
|
|
# according to those terms.
|
|
|
|
## LRU Cache for Epoch Indexed Hashimoto Cache
|
|
## ============================================
|
|
##
|
|
## This module uses the eth-block number (mapped to epoch) to hold and re-use
|
|
## the cache needed for running the `hasimotoLight()` proof-of-work function.
|
|
|
|
import
|
|
eth/common,
|
|
ethash,
|
|
stew/keyed_queue
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
type
|
|
PowCacheItemRef* = ref object
|
|
size*: uint64
|
|
data*: seq[MDigest[512]]
|
|
|
|
PowCacheStats* = tuple
|
|
maxItems: int
|
|
size: int
|
|
|
|
PowCache* = object
|
|
cacheMax: int
|
|
cache: KeyedQueue[uint64,PowCacheItemRef]
|
|
|
|
PowCacheRef* = ref PowCache
|
|
|
|
const
|
|
nItemsMax = 10
|
|
nItemsInit = 2
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc toKey(bn: BlockNumber): uint64 =
|
|
bn.truncate(uint64) div EPOCH_LENGTH
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions, constructor
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc init*(pc: var PowCache; maxItems = nItemsMax) =
|
|
## Constructor for PoW cache
|
|
pc.cacheMax = maxItems
|
|
pc.cache.init(nItemsInit)
|
|
|
|
proc init*(T: type PowCache; maxItems = nItemsMax): T =
|
|
## Constructor variant
|
|
result.init(maxItems)
|
|
|
|
proc new*(T: type PowCacheRef; maxItems = nItemsMax): T =
|
|
## Constructor variant
|
|
new result
|
|
result[].init(maxItems)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions, constructor
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc get*(pc: var PowCache; bn: BlockNumber): PowCacheItemRef
|
|
{.gcsafe, raises: [Defect, CatchableError].} =
|
|
## Return a cache derived from argument `blockNumber` ready to be used
|
|
## for the `hashimotoLight()` method.
|
|
let
|
|
key = bn.toKey
|
|
rc = pc.cache.lruFetch(key)
|
|
|
|
if rc.isOk:
|
|
return rc.value
|
|
|
|
let
|
|
# note that `getDataSize()` and `getCacheSize()` depend on
|
|
# `key * EPOCH_LENGTH` rather than the original block number.
|
|
top = key * EPOCH_LENGTH
|
|
pair = PowCacheItemRef(
|
|
size: top.getDataSize,
|
|
data: top.getCacheSize.mkcache(top.getSeedhash))
|
|
|
|
pc.cache.lruAppend(key, pair, pc.cacheMax)
|
|
|
|
proc get*(pcr: PowCacheRef; bn: BlockNumber): PowCacheItemRef
|
|
{.gcsafe, raises: [Defect, CatchableError].} =
|
|
## Variant of `getCache()`
|
|
pcr[].get(bn)
|
|
|
|
proc hasItem*(pc: var PowCache; bn: BlockNumber): bool
|
|
{.gcsafe,raises: [Defect,CatchableError].} =
|
|
## Returns true if there is a cache entry for argument `bn`.
|
|
pc.cache.hasKey(bn.toKey)
|
|
|
|
proc hasItem*(pcr: PowCacheRef; bn: BlockNumber): bool
|
|
{.gcsafe,raises: [Defect,CatchableError].} =
|
|
## Variant of `hasItem()`
|
|
pcr[].hasItem(bn)
|
|
|
|
# -------------------------
|
|
|
|
proc stats*(pc: var PowCache): PowCacheStats =
|
|
## Return current cache sizes
|
|
result = (maxItems: pc.cacheMax, size: pc.cache.len)
|
|
|
|
proc stats*(pcr: PowCacheRef): PowCacheStats =
|
|
## Variant of `stats()`
|
|
pcr[].stats
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|