core, cmd: add generic LRU implementation (#26162)

This commit is contained in:
Daniel Liu 2024-08-20 17:04:26 +08:00 committed by Daniel Liu
parent 96e2743508
commit c47819c7d6
5 changed files with 65 additions and 86 deletions

View file

@ -20,7 +20,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/ethdb/leveldb" "github.com/XinFinOrg/XDPoSChain/ethdb/leveldb"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru" "github.com/XinFinOrg/XDPoSChain/common/lru"
) )
var ( var (
@ -29,7 +29,7 @@ var (
sercureKey = []byte("secure-key-") sercureKey = []byte("secure-key-")
nWorker = runtime.NumCPU() / 2 nWorker = runtime.NumCPU() / 2
cleanAddress = []common.Address{common.BlockSignersBinary} cleanAddress = []common.Address{common.BlockSignersBinary}
cache *lru.Cache cache *lru.Cache[common.Hash, struct{}]
finish = int32(0) finish = int32(0)
running = true running = true
stateRoots = make(chan TrieRoot) stateRoots = make(chan TrieRoot)
@ -58,7 +58,7 @@ func main() {
currentHeader := core.GetHeader(lddb, head, core.GetBlockNumber(lddb, head)) currentHeader := core.GetHeader(lddb, head, core.GetBlockNumber(lddb, head))
tridb := trie.NewDatabase(lddb) tridb := trie.NewDatabase(lddb)
catchEventInterupt(db) catchEventInterupt(db)
cache, _ = lru.New(*cacheSize) cache = lru.NewCache[common.Hash, struct{}](*cacheSize)
go func() { go func() {
for i := uint64(1); i <= currentHeader.Number.Uint64(); i++ { for i := uint64(1); i <= currentHeader.Number.Uint64(); i++ {
hash := core.GetCanonicalHash(lddb, i) hash := core.GetCanonicalHash(lddb, i)
@ -222,7 +222,7 @@ func processNodes(node StateNode, db *leveldb.Database) ([17]*StateNode, [17]*[]
} }
} }
} }
cache.Add(commonHash, true) cache.Add(commonHash, struct{}{})
} }
return newNodes, keys, number return newNodes, keys, number
} }

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate" "github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/common/mclock" "github.com/XinFinOrg/XDPoSChain/common/mclock"
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/common/sort" "github.com/XinFinOrg/XDPoSChain/common/sort"
@ -52,7 +53,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
) )
var ( var (
@ -140,37 +140,40 @@ type BlockChain struct {
stateCache state.Database // State database to reuse between imports (contains state cache) stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies bodyCache *lru.Cache[common.Hash, *types.Body] // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] // Cache for the most recent block bodies in RLP encoded format
blockCache *lru.Cache // Cache for the most recent entire blocks blockCache *lru.Cache[common.Hash, *types.Block] // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing resultProcess *lru.Cache[common.Hash, *ResultProcessBlock] // Cache for processed blocks
resultProcess *lru.Cache // Cache for processed blocks calculatingBlock *lru.Cache[common.Hash, *CalculatedBlock] // Cache for processing blocks
calculatingBlock *lru.Cache // Cache for processing blocks downloadingBlock *lru.Cache[common.Hash, struct{}] // Cache for downloading blocks (avoid duplication from fetcher)
downloadingBlock *lru.Cache // Cache for downloading blocks (avoid duplication from fetcher) badBlocks *lru.Cache[common.Hash, *types.Header] // Bad block cache
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically // future blocks are blocks added for later processing
// procInterrupt must be atomically called futureBlocks *lru.Cache[common.Hash, *types.Block]
procInterrupt int32 // interrupt signaler for block processing
wg sync.WaitGroup // chain processing wait group for shutting down wg sync.WaitGroup // chain processing wait group for shutting down
quit chan struct{} // shutdown signal, closed in Stop.
running int32 // 0 if chain is running, 1 when stopped
procInterrupt int32 // interrupt signaler for block processing
engine consensus.Engine engine consensus.Engine
processor Processor // block processor interface processor Processor // block processor interface
validator Validator // block and state validator interface validator Validator // block and state validator interface
vmConfig vm.Config vmConfig vm.Config
badBlocks *lru.Cache // Bad block cache
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
IPCEndpoint string IPCEndpoint string
Client bind.ContractBackend // Global ipc client instance. Client bind.ContractBackend // Global ipc client instance.
// Blocks hash array by block number // Blocks hash array by block number
// cache field for tracking finality purpose, can't use for tracking block vs block relationship // cache field for tracking finality purpose, can't use for tracking block vs block relationship
blocksHashCache *lru.Cache blocksHashCache *lru.Cache[uint64, []common.Hash]
resultTrade *lru.Cache // trades result: key - takerOrderHash, value: trades corresponding to takerOrder resultTrade *lru.Cache[common.Hash, interface{}] // trades result: key - takerOrderHash, value: trades corresponding to takerOrder
rejectedOrders *lru.Cache // rejected orders: key - takerOrderHash, value: rejected orders corresponding to takerOrder rejectedOrders *lru.Cache[common.Hash, interface{}] // rejected orders: key - takerOrderHash, value: rejected orders corresponding to takerOrder
resultLendingTrade *lru.Cache resultLendingTrade *lru.Cache[common.Hash, interface{}]
rejectedLendingItem *lru.Cache rejectedLendingItem *lru.Cache[common.Hash, interface{}]
finalizedTrade *lru.Cache // include both trades which force update to closed/liquidated by the protocol finalizedTrade *lru.Cache[common.Hash, interface{}] // include both trades which force update to closed/liquidated by the protocol
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
@ -183,24 +186,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
TrieTimeLimit: 5 * time.Minute, TrieTimeLimit: 5 * time.Minute,
} }
} }
bodyCache, _ := lru.New(bodyCacheLimit)
bodyRLPCache, _ := lru.New(bodyCacheLimit)
blockCache, _ := lru.New(blockCacheLimit)
blocksHashCache, _ := lru.New(blocksHashCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)
resultProcess, _ := lru.New(blockCacheLimit)
preparingBlock, _ := lru.New(blockCacheLimit)
downloadingBlock, _ := lru.New(blockCacheLimit)
// for XDCx
resultTrade, _ := lru.New(tradingstate.OrderCacheLimit)
rejectedOrders, _ := lru.New(tradingstate.OrderCacheLimit)
// XDCxlending
resultLendingTrade, _ := lru.New(tradingstate.OrderCacheLimit)
rejectedLendingItem, _ := lru.New(tradingstate.OrderCacheLimit)
finalizedTrade, _ := lru.New(tradingstate.OrderCacheLimit)
bc := &BlockChain{ bc := &BlockChain{
chainConfig: chainConfig, chainConfig: chainConfig,
cacheConfig: cacheConfig, cacheConfig: cacheConfig,
@ -208,22 +194,22 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
triegc: prque.New(nil), triegc: prque.New(nil),
stateCache: state.NewDatabase(db), stateCache: state.NewDatabase(db),
quit: make(chan struct{}), quit: make(chan struct{}),
bodyCache: bodyCache, bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
bodyRLPCache: bodyRLPCache, bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit),
blockCache: blockCache, blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
futureBlocks: futureBlocks, futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks),
resultProcess: resultProcess, resultProcess: lru.NewCache[common.Hash, *ResultProcessBlock](blockCacheLimit),
calculatingBlock: preparingBlock, calculatingBlock: lru.NewCache[common.Hash, *CalculatedBlock](blockCacheLimit),
downloadingBlock: downloadingBlock, downloadingBlock: lru.NewCache[common.Hash, struct{}](blockCacheLimit),
engine: engine, engine: engine,
vmConfig: vmConfig, vmConfig: vmConfig,
badBlocks: badBlocks, badBlocks: lru.NewCache[common.Hash, *types.Header](badBlockLimit),
blocksHashCache: blocksHashCache, blocksHashCache: lru.NewCache[uint64, []common.Hash](blocksHashCacheLimit),
resultTrade: resultTrade, resultTrade: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
rejectedOrders: rejectedOrders, rejectedOrders: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
resultLendingTrade: resultLendingTrade, resultLendingTrade: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
rejectedLendingItem: rejectedLendingItem, rejectedLendingItem: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
finalizedTrade: finalizedTrade, finalizedTrade: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
} }
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@ -720,8 +706,7 @@ func (bc *BlockChain) Genesis() *types.Block {
func (bc *BlockChain) GetBody(hash common.Hash) *types.Body { func (bc *BlockChain) GetBody(hash common.Hash) *types.Body {
// Short circuit if the body's already in the cache, retrieve otherwise // Short circuit if the body's already in the cache, retrieve otherwise
if cached, ok := bc.bodyCache.Get(hash); ok { if cached, ok := bc.bodyCache.Get(hash); ok {
body := cached.(*types.Body) return cached
return body
} }
body := GetBody(bc.db, hash, bc.hc.GetBlockNumber(hash)) body := GetBody(bc.db, hash, bc.hc.GetBlockNumber(hash))
if body == nil { if body == nil {
@ -737,7 +722,7 @@ func (bc *BlockChain) GetBody(hash common.Hash) *types.Body {
func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue { func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {
// Short circuit if the body's already in the cache, retrieve otherwise // Short circuit if the body's already in the cache, retrieve otherwise
if cached, ok := bc.bodyRLPCache.Get(hash); ok { if cached, ok := bc.bodyRLPCache.Get(hash); ok {
return cached.(rlp.RawValue) return cached
} }
body := GetBodyRLP(bc.db, hash, bc.hc.GetBlockNumber(hash)) body := GetBodyRLP(bc.db, hash, bc.hc.GetBlockNumber(hash))
if len(body) == 0 { if len(body) == 0 {
@ -794,7 +779,7 @@ func (bc *BlockChain) HasBlockAndFullState(hash common.Hash, number uint64) bool
func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
// Short circuit if the block's already in the cache, retrieve otherwise // Short circuit if the block's already in the cache, retrieve otherwise
if block, ok := bc.blockCache.Get(hash); ok { if block, ok := bc.blockCache.Get(hash); ok {
return block.(*types.Block) return block
} }
block := GetBlock(bc.db, hash, number) block := GetBlock(bc.db, hash, number)
if block == nil { if block == nil {
@ -847,7 +832,7 @@ func (bc *BlockChain) GetBlocksHashCache(number uint64) []common.Hash {
cached, ok := bc.blocksHashCache.Get(number) cached, ok := bc.blocksHashCache.Get(number)
if ok { if ok {
return cached.([]common.Hash) return cached
} }
return nil return nil
} }
@ -980,7 +965,7 @@ func (bc *BlockChain) procFutureBlocks() {
blocks := make([]*types.Block, 0, bc.futureBlocks.Len()) blocks := make([]*types.Block, 0, bc.futureBlocks.Len())
for _, hash := range bc.futureBlocks.Keys() { for _, hash := range bc.futureBlocks.Keys() {
if block, exist := bc.futureBlocks.Peek(hash); exist { if block, exist := bc.futureBlocks.Peek(hash); exist {
blocks = append(blocks, block.(*types.Block)) blocks = append(blocks, block)
} }
} }
if len(blocks) > 0 { if len(blocks) > 0 {
@ -1491,7 +1476,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []
for i, block := range chain { for i, block := range chain {
headers[i] = block.Header() headers[i] = block.Header()
seals[i] = verifySeals seals[i] = verifySeals
bc.downloadingBlock.Add(block.Hash(), true) bc.downloadingBlock.Add(block.Hash(), struct{}{})
} }
abort, results := bc.engine.VerifyHeaders(bc, headers, seals) abort, results := bc.engine.VerifyHeaders(bc, headers, seals)
defer close(abort) defer close(abort)
@ -1805,11 +1790,11 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu
if verifiedM2 { if verifiedM2 {
if result, check := bc.resultProcess.Get(block.HashNoValidator()); check { if result, check := bc.resultProcess.Get(block.HashNoValidator()); check {
log.Debug("Get result block from cache ", "number", block.NumberU64(), "hash", block.Hash(), "hash no validator", block.HashNoValidator()) log.Debug("Get result block from cache ", "number", block.NumberU64(), "hash", block.Hash(), "hash no validator", block.HashNoValidator())
return result.(*ResultProcessBlock), nil return result, nil
} }
log.Debug("Not found cache prepare block ", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.HashNoValidator()) log.Debug("Not found cache prepare block ", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.HashNoValidator())
if calculatedBlock, _ := bc.calculatingBlock.Get(block.HashNoValidator()); calculatedBlock != nil { if calculatedBlock, _ := bc.calculatingBlock.Get(block.HashNoValidator()); calculatedBlock != nil {
calculatedBlock.(*CalculatedBlock).stop = true calculatedBlock.stop = true
} }
} }
calculatedBlock = &CalculatedBlock{block, false} calculatedBlock = &CalculatedBlock{block, false}
@ -2007,7 +1992,7 @@ func (bc *BlockChain) UpdateBlocksHashCache(block *types.Block) []common.Hash {
cached, ok := bc.blocksHashCache.Get(blockNumber) cached, ok := bc.blocksHashCache.Get(blockNumber)
if ok { if ok {
hashArr := cached.([]common.Hash) hashArr := cached
hashArr = append(hashArr, block.Hash()) hashArr = append(hashArr, block.Hash())
bc.blocksHashCache.Remove(blockNumber) bc.blocksHashCache.Remove(blockNumber)
bc.blocksHashCache.Add(blockNumber, hashArr) bc.blocksHashCache.Add(blockNumber, hashArr)
@ -2340,8 +2325,7 @@ type BadBlockArgs struct {
func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) { func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) {
headers := make([]BadBlockArgs, 0, bc.badBlocks.Len()) headers := make([]BadBlockArgs, 0, bc.badBlocks.Len())
for _, hash := range bc.badBlocks.Keys() { for _, hash := range bc.badBlocks.Keys() {
if hdr, exist := bc.badBlocks.Peek(hash); exist { if header, exist := bc.badBlocks.Peek(hash); exist {
header := hdr.(*types.Header)
headers = append(headers, BadBlockArgs{header.Hash(), header}) headers = append(headers, BadBlockArgs{header.Hash(), header})
} }
} }

View file

@ -1367,7 +1367,7 @@ func TestBlocksHashCacheUpdate(t *testing.T) {
} }
cachedAt, _ := chain.blocksHashCache.Get(uint64(3)) cachedAt, _ := chain.blocksHashCache.Get(uint64(3))
if len(cachedAt.([]common.Hash)) != 2 { if len(cachedAt) != 2 {
t.Error("BlocksHashCache doesn't add new cache after concating new fork ") t.Error("BlocksHashCache doesn't add new cache after concating new fork ")
} }
}) })

View file

@ -27,13 +27,13 @@ import (
"time" "time"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
lru "github.com/hashicorp/golang-lru"
) )
const ( const (
@ -56,9 +56,9 @@ type HeaderChain struct {
currentHeader atomic.Value // Current head of the header chain (may be above the block chain!) currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time)
headerCache *lru.Cache // Cache for the most recent block headers headerCache *lru.Cache[common.Hash, *types.Header]
tdCache *lru.Cache // Cache for the most recent block total difficulties tdCache *lru.Cache[common.Hash, *big.Int] // most recent total difficulties
numberCache *lru.Cache // Cache for the most recent block numbers numberCache *lru.Cache[common.Hash, uint64] // most recent block numbers
procInterrupt func() bool procInterrupt func() bool
@ -72,10 +72,6 @@ type HeaderChain struct {
// procInterrupt points to the parent's interrupt semaphore // procInterrupt points to the parent's interrupt semaphore
// wg points to the parent's shutdown wait group // wg points to the parent's shutdown wait group
func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) {
headerCache, _ := lru.New(headerCacheLimit)
tdCache, _ := lru.New(tdCacheLimit)
numberCache, _ := lru.New(numberCacheLimit)
// Seed a fast but crypto originating random generator // Seed a fast but crypto originating random generator
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
if err != nil { if err != nil {
@ -85,9 +81,9 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
hc := &HeaderChain{ hc := &HeaderChain{
config: config, config: config,
chainDb: chainDb, chainDb: chainDb,
headerCache: headerCache, headerCache: lru.NewCache[common.Hash, *types.Header](headerCacheLimit),
tdCache: tdCache, tdCache: lru.NewCache[common.Hash, *big.Int](tdCacheLimit),
numberCache: numberCache, numberCache: lru.NewCache[common.Hash, uint64](numberCacheLimit),
procInterrupt: procInterrupt, procInterrupt: procInterrupt,
rand: mrand.New(mrand.NewSource(seed.Int64())), rand: mrand.New(mrand.NewSource(seed.Int64())),
engine: engine, engine: engine,
@ -113,7 +109,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
// from the cache or database // from the cache or database
func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 { func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 {
if cached, ok := hc.numberCache.Get(hash); ok { if cached, ok := hc.numberCache.Get(hash); ok {
return cached.(uint64) return cached
} }
number := GetBlockNumber(hc.chainDb, hash) number := GetBlockNumber(hc.chainDb, hash)
if number != missingNumber { if number != missingNumber {
@ -312,7 +308,7 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
// Short circuit if the td's already in the cache, retrieve otherwise // Short circuit if the td's already in the cache, retrieve otherwise
if cached, ok := hc.tdCache.Get(hash); ok { if cached, ok := hc.tdCache.Get(hash); ok {
return cached.(*big.Int) return cached
} }
td := GetTd(hc.chainDb, hash, number) td := GetTd(hc.chainDb, hash, number)
if td == nil { if td == nil {
@ -344,7 +340,7 @@ func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) err
func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header {
// Short circuit if the header's already in the cache, retrieve otherwise // Short circuit if the header's already in the cache, retrieve otherwise
if header, ok := hc.headerCache.Get(hash); ok { if header, ok := hc.headerCache.Get(hash); ok {
return header.(*types.Header) return header
} }
header := GetHeader(hc.chainDb, hash, number) header := GetHeader(hc.chainDb, hash, number)
if header == nil { if header == nil {

View file

@ -20,9 +20,9 @@ import (
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
) )
const ( const (
@ -107,16 +107,15 @@ func NewDatabase(db ethdb.Database) Database {
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a // is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
// large memory cache. // large memory cache.
func NewDatabaseWithCache(db ethdb.Database, cache int) Database { func NewDatabaseWithCache(db ethdb.Database, cache int) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{ return &cachingDB{
db: trie.NewDatabaseWithCache(db, cache), db: trie.NewDatabaseWithCache(db, cache),
codeSizeCache: csc, codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
} }
} }
type cachingDB struct { type cachingDB struct {
db *trie.Database db *trie.Database
codeSizeCache *lru.Cache codeSizeCache *lru.Cache[common.Hash, int]
} }
// OpenTrie opens the main account trie at a specific root hash. // OpenTrie opens the main account trie at a specific root hash.
@ -151,7 +150,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error
// ContractCodeSize retrieves a particular contracts code's size. // ContractCodeSize retrieves a particular contracts code's size.
func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
if cached, ok := db.codeSizeCache.Get(codeHash); ok { if cached, ok := db.codeSizeCache.Get(codeHash); ok {
return cached.(int), nil return cached, nil
} }
code, err := db.ContractCode(addrHash, codeHash) code, err := db.ContractCode(addrHash, codeHash)
return len(code), err return len(code), err