Skip to content

Commit 50e9e57

Browse files
committed
chore: use mempool from Tendermint v0.34.20
mempool was copied from tendermint v0.34.20 It was adapted to make it compatible: - tmsync package was removed (sync used instead) - clist copied to mempool/, imports fixed - v0 removed - v1/reactor.go removed Changes in node, rpc, state packages was caused by changes in mempool API.
1 parent 75a387a commit 50e9e57

26 files changed

Lines changed: 2706 additions & 1744 deletions

mempool/bench_test.go

Lines changed: 0 additions & 73 deletions
This file was deleted.

mempool/cache.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package mempool
2+
3+
import (
4+
"container/list"
5+
6+
"github.com/tendermint/tendermint/types"
7+
"sync"
8+
)
9+
10+
// TxCache defines an interface for raw transaction caching in a mempool.
11+
// Currently, a TxCache does not allow direct reading or getting of transaction
12+
// values. A TxCache is used primarily to push transactions and removing
13+
// transactions. Pushing via Push returns a boolean telling the caller if the
14+
// transaction already exists in the cache or not.
15+
type TxCache interface {
16+
// Reset resets the cache to an empty state.
17+
Reset()
18+
19+
// Push adds the given raw transaction to the cache and returns true if it was
20+
// newly added. Otherwise, it returns false.
21+
Push(tx types.Tx) bool
22+
23+
// Remove removes the given raw transaction from the cache.
24+
Remove(tx types.Tx)
25+
26+
// Has reports whether tx is present in the cache. Checking for presence is
27+
// not treated as an access of the value.
28+
Has(tx types.Tx) bool
29+
}
30+
31+
var _ TxCache = (*LRUTxCache)(nil)
32+
33+
// LRUTxCache maintains a thread-safe LRU cache of raw transactions. The cache
34+
// only stores the hash of the raw transaction.
35+
type LRUTxCache struct {
36+
mtx sync.Mutex
37+
size int
38+
cacheMap map[types.TxKey]*list.Element
39+
list *list.List
40+
}
41+
42+
func NewLRUTxCache(cacheSize int) *LRUTxCache {
43+
return &LRUTxCache{
44+
size: cacheSize,
45+
cacheMap: make(map[types.TxKey]*list.Element, cacheSize),
46+
list: list.New(),
47+
}
48+
}
49+
50+
// GetList returns the underlying linked-list that backs the LRU cache. Note,
51+
// this should be used for testing purposes only!
52+
func (c *LRUTxCache) GetList() *list.List {
53+
return c.list
54+
}
55+
56+
func (c *LRUTxCache) Reset() {
57+
c.mtx.Lock()
58+
defer c.mtx.Unlock()
59+
60+
c.cacheMap = make(map[types.TxKey]*list.Element, c.size)
61+
c.list.Init()
62+
}
63+
64+
func (c *LRUTxCache) Push(tx types.Tx) bool {
65+
c.mtx.Lock()
66+
defer c.mtx.Unlock()
67+
68+
key := tx.Key()
69+
70+
moved, ok := c.cacheMap[key]
71+
if ok {
72+
c.list.MoveToBack(moved)
73+
return false
74+
}
75+
76+
if c.list.Len() >= c.size {
77+
front := c.list.Front()
78+
if front != nil {
79+
frontKey := front.Value.(types.TxKey)
80+
delete(c.cacheMap, frontKey)
81+
c.list.Remove(front)
82+
}
83+
}
84+
85+
e := c.list.PushBack(key)
86+
c.cacheMap[key] = e
87+
88+
return true
89+
}
90+
91+
func (c *LRUTxCache) Remove(tx types.Tx) {
92+
c.mtx.Lock()
93+
defer c.mtx.Unlock()
94+
95+
key := tx.Key()
96+
e := c.cacheMap[key]
97+
delete(c.cacheMap, key)
98+
99+
if e != nil {
100+
c.list.Remove(e)
101+
}
102+
}
103+
104+
func (c *LRUTxCache) Has(tx types.Tx) bool {
105+
c.mtx.Lock()
106+
defer c.mtx.Unlock()
107+
108+
_, ok := c.cacheMap[tx.Key()]
109+
return ok
110+
}
111+
112+
// NopTxCache defines a no-op raw transaction cache.
113+
type NopTxCache struct{}
114+
115+
var _ TxCache = (*NopTxCache)(nil)
116+
117+
func (NopTxCache) Reset() {}
118+
func (NopTxCache) Push(types.Tx) bool { return true }
119+
func (NopTxCache) Remove(types.Tx) {}
120+
func (NopTxCache) Has(types.Tx) bool { return false }

mempool/cache_bench_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package mempool
2+
3+
import (
4+
"encoding/binary"
5+
"testing"
6+
)
7+
8+
func BenchmarkCacheInsertTime(b *testing.B) {
9+
cache := NewLRUTxCache(b.N)
10+
11+
txs := make([][]byte, b.N)
12+
for i := 0; i < b.N; i++ {
13+
txs[i] = make([]byte, 8)
14+
binary.BigEndian.PutUint64(txs[i], uint64(i))
15+
}
16+
17+
b.ResetTimer()
18+
19+
for i := 0; i < b.N; i++ {
20+
cache.Push(txs[i])
21+
}
22+
}
23+
24+
// This benchmark is probably skewed, since we actually will be removing
25+
// txs in parallel, which may cause some overhead due to mutex locking.
26+
func BenchmarkCacheRemoveTime(b *testing.B) {
27+
cache := NewLRUTxCache(b.N)
28+
29+
txs := make([][]byte, b.N)
30+
for i := 0; i < b.N; i++ {
31+
txs[i] = make([]byte, 8)
32+
binary.BigEndian.PutUint64(txs[i], uint64(i))
33+
cache.Push(txs[i])
34+
}
35+
36+
b.ResetTimer()
37+
38+
for i := 0; i < b.N; i++ {
39+
cache.Remove(txs[i])
40+
}
41+
}

mempool/cache_test.go

Lines changed: 5 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,34 @@ package mempool
22

33
import (
44
"crypto/rand"
5-
"crypto/sha256"
65
"testing"
76

87
"github.com/stretchr/testify/require"
9-
10-
"github.com/tendermint/tendermint/abci/example/kvstore"
11-
abci "github.com/tendermint/tendermint/abci/types"
12-
"github.com/tendermint/tendermint/proxy"
13-
"github.com/tendermint/tendermint/types"
148
)
159

1610
func TestCacheRemove(t *testing.T) {
17-
cache := newMapTxCache(100)
11+
cache := NewLRUTxCache(100)
1812
numTxs := 10
13+
1914
txs := make([][]byte, numTxs)
2015
for i := 0; i < numTxs; i++ {
2116
// probability of collision is 2**-256
2217
txBytes := make([]byte, 32)
2318
_, err := rand.Read(txBytes)
2419
require.NoError(t, err)
20+
2521
txs[i] = txBytes
2622
cache.Push(txBytes)
23+
2724
// make sure its added to both the linked list and the map
2825
require.Equal(t, i+1, len(cache.cacheMap))
2926
require.Equal(t, i+1, cache.list.Len())
3027
}
28+
3129
for i := 0; i < numTxs; i++ {
3230
cache.Remove(txs[i])
3331
// make sure its removed from both the map and the linked list
3432
require.Equal(t, numTxs-(i+1), len(cache.cacheMap))
3533
require.Equal(t, numTxs-(i+1), cache.list.Len())
3634
}
3735
}
38-
39-
func TestCacheAfterUpdate(t *testing.T) {
40-
app := kvstore.NewApplication()
41-
cc := proxy.NewLocalClientCreator(app)
42-
mempool, cleanup := newMempoolWithApp(cc)
43-
defer cleanup()
44-
45-
// reAddIndices & txsInCache can have elements > numTxsToCreate
46-
// also assumes max index is 255 for convenience
47-
// txs in cache also checks order of elements
48-
tests := []struct {
49-
numTxsToCreate int
50-
updateIndices []int
51-
reAddIndices []int
52-
txsInCache []int
53-
}{
54-
{1, []int{}, []int{1}, []int{1, 0}}, // adding new txs works
55-
{2, []int{1}, []int{}, []int{1, 0}}, // update doesn't remove tx from cache
56-
{2, []int{2}, []int{}, []int{2, 1, 0}}, // update adds new tx to cache
57-
{2, []int{1}, []int{1}, []int{1, 0}}, // re-adding after update doesn't make dupe
58-
}
59-
for tcIndex, tc := range tests {
60-
for i := 0; i < tc.numTxsToCreate; i++ {
61-
tx := types.Tx{byte(i)}
62-
err := mempool.CheckTx(tx, nil, TxInfo{})
63-
require.NoError(t, err)
64-
}
65-
66-
updateTxs := []types.Tx{}
67-
for _, v := range tc.updateIndices {
68-
tx := types.Tx{byte(v)}
69-
updateTxs = append(updateTxs, tx)
70-
}
71-
err := mempool.Update(int64(tcIndex), updateTxs, abciResponses(len(updateTxs), abci.CodeTypeOK), nil, nil)
72-
require.NoError(t, err)
73-
74-
for _, v := range tc.reAddIndices {
75-
tx := types.Tx{byte(v)}
76-
_ = mempool.CheckTx(tx, nil, TxInfo{})
77-
}
78-
79-
cache := mempool.cache.(*mapTxCache)
80-
node := cache.list.Front()
81-
counter := 0
82-
for node != nil {
83-
require.NotEqual(t, len(tc.txsInCache), counter,
84-
"cache larger than expected on testcase %d", tcIndex)
85-
86-
nodeVal := node.Value.([sha256.Size]byte)
87-
expectedBz := sha256.Sum256([]byte{byte(tc.txsInCache[len(tc.txsInCache)-counter-1])})
88-
// Reference for reading the errors:
89-
// >>> sha256('\x00').hexdigest()
90-
// '6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d'
91-
// >>> sha256('\x01').hexdigest()
92-
// '4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a'
93-
// >>> sha256('\x02').hexdigest()
94-
// 'dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d986'
95-
96-
require.Equal(t, expectedBz, nodeVal, "Equality failed on index %d, tc %d", counter, tcIndex)
97-
counter++
98-
node = node.Next()
99-
}
100-
require.Equal(t, len(tc.txsInCache), counter,
101-
"cache smaller than expected on testcase %d", tcIndex)
102-
mempool.Flush()
103-
}
104-
}

mempool/clist/bench_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package clist
2+
3+
import "testing"
4+
5+
func BenchmarkDetaching(b *testing.B) {
6+
lst := New()
7+
for i := 0; i < b.N+1; i++ {
8+
lst.PushBack(i)
9+
}
10+
start := lst.Front()
11+
nxt := start.Next()
12+
b.ResetTimer()
13+
for i := 0; i < b.N; i++ {
14+
start.removed = true
15+
start.DetachNext()
16+
start.DetachPrev()
17+
tmp := nxt
18+
nxt = nxt.Next()
19+
start = tmp
20+
}
21+
}
22+
23+
// This is used to benchmark the time of RMutex.
24+
func BenchmarkRemoved(b *testing.B) {
25+
lst := New()
26+
for i := 0; i < b.N+1; i++ {
27+
lst.PushBack(i)
28+
}
29+
start := lst.Front()
30+
nxt := start.Next()
31+
b.ResetTimer()
32+
for i := 0; i < b.N; i++ {
33+
start.Removed()
34+
tmp := nxt
35+
nxt = nxt.Next()
36+
start = tmp
37+
}
38+
}
39+
40+
func BenchmarkPushBack(b *testing.B) {
41+
lst := New()
42+
b.ResetTimer()
43+
for i := 0; i < b.N; i++ {
44+
lst.PushBack(i)
45+
}
46+
}

0 commit comments

Comments
 (0)