aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-12-21 16:35:08 +0800
committerWei-Ning Huang <w@dexon.org>2019-03-12 12:19:09 +0800
commit65cb7fbf62088ad5ffb5a87bd6d47dfb6870103e (patch)
tree9d4b5176ae9811f6b58834610af93c8ae81fbb2b
parentf5522f0ffcbe127a8fd364647848be46ecc68cda (diff)
downloaddexon-65cb7fbf62088ad5ffb5a87bd6d47dfb6870103e.tar.gz
dexon-65cb7fbf62088ad5ffb5a87bd6d47dfb6870103e.tar.zst
dexon-65cb7fbf62088ad5ffb5a87bd6d47dfb6870103e.zip
core/types: SigCache with a limited size (#98)
* core/types: SigCache with a limited size * minor tweaks
-rw-r--r--core/tx_pool.go1
-rw-r--r--core/types/transaction_signing.go53
2 files changed, 33 insertions, 21 deletions
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 911b6c261..546ef0a99 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -874,7 +874,6 @@ func (pool *TxPool) Get(hash common.Hash) *types.Transaction {
// removeTx removes a single transaction from the queue, moving all subsequent
// transactions back to the future queue.
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
- types.GlobalSigCache.Prune([]common.Hash{hash})
// Fetch the transaction we wish to delete
tx := pool.all.Get(hash)
if tx == nil {
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index 1a13e3e3d..04abeb402 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -39,25 +39,32 @@ func init() {
GlobalSigCache = newGlobalSigCache()
}
+type resultEntry struct {
+ Hash common.Hash
+ Addr common.Address
+}
+
+// SigCache has maximum of `sigCacheSize` and will be purged to `pruneTargetSize`
+// if exceeding `sigCacheSize`.
+const sigCacheSize = 100000
+const pruneTargetSize = 90000
+
// globalSigCache stores the mapping between txHash and sender address.
// Since ECRecover is slow, and we run ECRecover very frequently (in
// app.VerifyBlock, app.ConfirmedBlock), so we need to cache it globally.
type globalSigCache struct {
- cache map[common.Hash]common.Address
+ cacheID map[common.Hash]int
+ cache []resultEntry
cacheMu sync.RWMutex
}
func newGlobalSigCache() *globalSigCache {
return &globalSigCache{
- cache: make(map[common.Hash]common.Address),
+ cacheID: make(map[common.Hash]int, sigCacheSize),
+ cache: make([]resultEntry, 0, sigCacheSize),
}
}
-type resultEntry struct {
- Hash common.Hash
- Addr common.Address
-}
-
// Add adds a list of transactions into sig cache.
func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transaction, err error) {
num := runtime.NumCPU() - 2
@@ -94,8 +101,22 @@ func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transact
// Acquire lock and set cache.
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
+ for len(results)+len(c.cacheID) > sigCacheSize {
+ if len(results) > sigCacheSize {
+ // Purge all cache.
+ c.cacheID = make(map[common.Hash]int, len(results))
+ c.cache = c.cache[:0]
+ break
+ }
+ var prune []resultEntry
+ c.cache, prune = c.cache[:pruneTargetSize], c.cache[pruneTargetSize:]
+ for _, r := range prune {
+ delete(c.cacheID, r.Hash)
+ }
+ }
for _, r := range results {
- c.cache[r.Hash] = r.Addr
+ c.cacheID[r.Hash] = len(c.cache)
+ c.cache = append(c.cache, r)
}
}(txs[i*batchSize : (i+1)*batchSize])
}
@@ -108,23 +129,15 @@ func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transact
return
}
-// Prune removes a list of hashes of tx from the cache.
-func (c *globalSigCache) Prune(hashes []common.Hash) {
- c.cacheMu.Lock()
- defer c.cacheMu.Unlock()
-
- for _, hash := range hashes {
- delete(c.cache, hash)
- }
-}
-
// Get returns a single address given a tx hash.
func (c *globalSigCache) Get(hash common.Hash) (common.Address, bool) {
c.cacheMu.RLock()
defer c.cacheMu.RUnlock()
- res, ok := c.cache[hash]
- return res, ok
+ if ID, ok := c.cacheID[hash]; ok {
+ return c.cache[ID].Addr, true
+ }
+ return common.Address{}, false
}
// sigCache is used to cache the derived sender and contains