--- /dev/null
+package common
+
+import (
+ "sync"
+
+ "github.com/golang/groupcache/lru"
+)
+
+// Cache is an LRU cache. It is safe for concurrent access.
+type Cache struct {
+ cache *lru.Cache
+ sync.RWMutex
+}
+
+// NewCache creates a new Cache.
+// If maxEntries is zero, the cache has no limit and it's assumed
+// that eviction is done by the caller.
+func NewCache(maxEntries int) *Cache {
+ return &Cache{cache: lru.New(maxEntries)}
+}
+
+// Add adds a value to the cache.
+func (c *Cache) Add(key, value interface{}) {
+ c.Lock()
+ defer c.Unlock()
+ c.cache.Add(key, value)
+}
+
+// Get looks up a key's value from the cache.
+func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
+ c.Lock()
+ defer c.Unlock()
+ return c.cache.Get(key)
+}
+
+// Remove removes the provided key from the cache.
+func (c *Cache) Remove(key interface{}) {
+ c.Lock()
+ defer c.Unlock()
+ c.cache.Remove(key)
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *Cache) RemoveOldest() {
+ c.Lock()
+ defer c.Unlock()
+ c.cache.RemoveOldest()
+}
+
+// Len returns the number of items in the cache.
+func (c *Cache) Len() int {
+ c.RLock()
+ defer c.RUnlock()
+ return c.cache.Len()
+}
+
+// Clear purges all stored items from the cache.
+func (c *Cache) Clear() {
+ c.Lock()
+ defer c.Unlock()
+ c.cache.Clear()
+}
"encoding/hex"
"sync"
+ "github.com/bytom/bytom/common"
"github.com/bytom/bytom/errors"
"github.com/bytom/bytom/math/checked"
"github.com/bytom/bytom/protocol"
// pubKey -> conflicting verifications
evilValidators map[string][]*Verification
+ // block hash -> previous checkpoint hash
+ prevCheckpointCache *common.Cache
}
// Best chain return the chain containing the justified checkpoint of the largest height
return nil, err
}
- c.mu.RLock()
- defer c.mu.RUnlock()
-
checkpoint, err := c.store.GetCheckpoint(hash)
if err != nil {
return nil, err
}
func (c *Casper) prevCheckpointHash(blockHash *bc.Hash) (*bc.Hash, error) {
+ if data, ok := c.prevCheckpointCache.Get(blockHash); ok {
+ return data.(*bc.Hash), nil
+ }
+
for {
block, err := c.store.GetBlockHeader(blockHash)
if err != nil {
return nil, err
}
- height := block.Height - 1
- blockHash = &block.PreviousBlockHash
- if height%state.BlocksOfEpoch == 0 {
- return blockHash, nil
+ prevHeight, prevHash := block.Height-1, block.PreviousBlockHash
+ if data, ok := c.prevCheckpointCache.Get(prevHash); ok {
+ return data.(*bc.Hash), nil
+ }
+
+ if prevHeight%state.BlocksOfEpoch == 0 {
+ c.prevCheckpointCache.Add(blockHash, &prevHash)
+ return &prevHash, nil
}
+
+ blockHash = &prevHash
}
}