[wallet] Nonce range cache
This commit is contained in:
parent
f75f7bb738
commit
66fbfc1daf
|
@ -3,15 +3,24 @@ package wallet
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type nonceRange struct {
|
||||||
|
nonce int64
|
||||||
|
max *big.Int
|
||||||
|
min *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
type balanceCache struct {
|
type balanceCache struct {
|
||||||
// balances maps an address to a map of a block number and the balance of this particular address
|
// balances maps an address to a map of a block number and the balance of this particular address
|
||||||
balances map[common.Address]map[*big.Int]*big.Int
|
balances map[common.Address]map[*big.Int]*big.Int
|
||||||
nonces map[common.Address]map[*big.Int]*int64
|
nonces map[common.Address]map[*big.Int]*int64
|
||||||
|
nonceRanges map[common.Address]map[int64]nonceRange
|
||||||
|
sortedRanges map[common.Address][]nonceRange
|
||||||
rw sync.RWMutex
|
rw sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +68,69 @@ func (b *balanceCache) ReadCachedNonce(account common.Address, blockNumber *big.
|
||||||
return b.nonces[account][blockNumber]
|
return b.nonces[account][blockNumber]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *balanceCache) sortRanges(account common.Address) {
|
||||||
|
keys := make([]int, 0, len(b.nonceRanges[account]))
|
||||||
|
for k := range b.nonceRanges[account] {
|
||||||
|
keys = append(keys, int(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Ints(keys)
|
||||||
|
|
||||||
|
ranges := []nonceRange{}
|
||||||
|
for _, k := range keys {
|
||||||
|
r := b.nonceRanges[account][int64(k)]
|
||||||
|
ranges = append(ranges, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.sortedRanges[account] = ranges
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceCache) findNonceInRange(account common.Address, block *big.Int) *int64 {
|
||||||
|
for k := range b.sortedRanges[account] {
|
||||||
|
nr := b.sortedRanges[account][k]
|
||||||
|
cmpMin := nr.min.Cmp(block)
|
||||||
|
if cmpMin == 1 {
|
||||||
|
return nil
|
||||||
|
} else if cmpMin == 0 {
|
||||||
|
return &nr.nonce
|
||||||
|
} else {
|
||||||
|
cmpMax := nr.max.Cmp(block)
|
||||||
|
if cmpMax >= 0 {
|
||||||
|
return &nr.nonce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceCache) updateNonceRange(account common.Address, blockNumber *big.Int, nonce *int64) {
|
||||||
|
_, exists := b.nonceRanges[account]
|
||||||
|
if !exists {
|
||||||
|
b.nonceRanges[account] = make(map[int64]nonceRange)
|
||||||
|
}
|
||||||
|
nr, exists := b.nonceRanges[account][*nonce]
|
||||||
|
if !exists {
|
||||||
|
r := nonceRange{
|
||||||
|
max: big.NewInt(0).Set(blockNumber),
|
||||||
|
min: big.NewInt(0).Set(blockNumber),
|
||||||
|
nonce: *nonce,
|
||||||
|
}
|
||||||
|
b.nonceRanges[account][*nonce] = r
|
||||||
|
} else {
|
||||||
|
if nr.max.Cmp(blockNumber) == -1 {
|
||||||
|
nr.max.Set(blockNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nr.min.Cmp(blockNumber) == 1 {
|
||||||
|
nr.min.Set(blockNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.nonceRanges[account][*nonce] = nr
|
||||||
|
b.sortRanges(account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *balanceCache) addNonceToCache(account common.Address, blockNumber *big.Int, nonce *int64) {
|
func (b *balanceCache) addNonceToCache(account common.Address, blockNumber *big.Int, nonce *int64) {
|
||||||
b.rw.Lock()
|
b.rw.Lock()
|
||||||
defer b.rw.Unlock()
|
defer b.rw.Unlock()
|
||||||
|
@ -68,6 +140,7 @@ func (b *balanceCache) addNonceToCache(account common.Address, blockNumber *big.
|
||||||
b.nonces[account] = make(map[*big.Int]*int64)
|
b.nonces[account] = make(map[*big.Int]*int64)
|
||||||
}
|
}
|
||||||
b.nonces[account][blockNumber] = nonce
|
b.nonces[account][blockNumber] = nonce
|
||||||
|
b.updateNonceRange(account, blockNumber, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *balanceCache) NonceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*int64, error) {
|
func (b *balanceCache) NonceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*int64, error) {
|
||||||
|
@ -75,6 +148,12 @@ func (b *balanceCache) NonceAt(ctx context.Context, client BalanceReader, accoun
|
||||||
if cachedNonce != nil {
|
if cachedNonce != nil {
|
||||||
return cachedNonce, nil
|
return cachedNonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rangeNonce := b.findNonceInRange(account, blockNumber)
|
||||||
|
if rangeNonce != nil {
|
||||||
|
return rangeNonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
nonce, err := client.NonceAt(ctx, account, blockNumber)
|
nonce, err := client.NonceAt(ctx, account, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -89,5 +168,7 @@ func newBalanceCache() *balanceCache {
|
||||||
return &balanceCache{
|
return &balanceCache{
|
||||||
balances: make(map[common.Address]map[*big.Int]*big.Int),
|
balances: make(map[common.Address]map[*big.Int]*big.Int),
|
||||||
nonces: make(map[common.Address]map[*big.Int]*int64),
|
nonces: make(map[common.Address]map[*big.Int]*int64),
|
||||||
|
nonceRanges: make(map[common.Address]map[int64]nonceRange),
|
||||||
|
sortedRanges: make(map[common.Address][]nonceRange),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue