-
Notifications
You must be signed in to change notification settings - Fork 246
/
balance_cache.go
94 lines (75 loc) · 2.32 KB
/
balance_cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package wallet
import (
"context"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
)
type balanceCache struct {
// cache maps an address to a map of a block number and the balance of this particular address
cache map[common.Address]map[*big.Int]*big.Int
requestCounter map[common.Address]uint
cacheHitsCounter map[common.Address]uint
rw sync.RWMutex
}
type BalanceCache interface {
BalanceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*big.Int, error)
}
func (b *balanceCache) readCachedBalance(account common.Address, blockNumber *big.Int) *big.Int {
b.rw.RLock()
defer b.rw.RUnlock()
return b.cache[account][blockNumber]
}
func (b *balanceCache) addBalanceToCache(account common.Address, blockNumber *big.Int, balance *big.Int) {
b.rw.Lock()
defer b.rw.Unlock()
_, exists := b.cache[account]
if !exists {
b.cache[account] = make(map[*big.Int]*big.Int)
}
b.cache[account][blockNumber] = balance
}
func (b *balanceCache) incRequestsNumber(account common.Address) {
b.rw.Lock()
defer b.rw.Unlock()
cnt, ok := b.requestCounter[account]
if !ok {
b.requestCounter[account] = 1
}
b.requestCounter[account] = cnt + 1
}
func (b *balanceCache) incCacheHitNumber(account common.Address) {
b.rw.Lock()
defer b.rw.Unlock()
cnt, ok := b.cacheHitsCounter[account]
if !ok {
b.cacheHitsCounter[account] = 1
}
b.cacheHitsCounter[account] = cnt + 1
}
func (b *balanceCache) getStats(account common.Address) (uint, uint) {
b.rw.RLock()
defer b.rw.RUnlock()
return b.requestCounter[account], b.cacheHitsCounter[account]
}
func (b *balanceCache) BalanceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*big.Int, error) {
b.incRequestsNumber(account)
cachedBalance := b.readCachedBalance(account, blockNumber)
if cachedBalance != nil {
b.incCacheHitNumber(account)
return cachedBalance, nil
}
balance, err := client.BalanceAt(ctx, account, blockNumber)
if err != nil {
return nil, err
}
b.addBalanceToCache(account, blockNumber, balance)
return balance, nil
}
func newBalanceCache() *balanceCache {
return &balanceCache{
cache: make(map[common.Address]map[*big.Int]*big.Int),
requestCounter: make(map[common.Address]uint),
cacheHitsCounter: make(map[common.Address]uint),
}
}