-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dot/network): Add cache for network message. (#1511)
* Add cache for network message.
- Loading branch information
Showing
8 changed files
with
259 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package network | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
"github.com/dgraph-io/ristretto" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
) | ||
|
||
// msgCacheTTL is default duration a key-value will be stored in messageCache. | ||
var msgCacheTTL = 5 * time.Minute | ||
|
||
// messageCache is used to detect duplicated messages per peer. | ||
type messageCache struct { | ||
cache *ristretto.Cache | ||
ttl time.Duration | ||
} | ||
|
||
// newMessageCache creates a new messageCache which takes config and TTL duration. | ||
func newMessageCache(config ristretto.Config, ttl time.Duration) (*messageCache, error) { | ||
cache, err := ristretto.NewCache(&config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if ttl == 0 { | ||
ttl = msgCacheTTL | ||
} | ||
|
||
return &messageCache{cache: cache, ttl: ttl}, nil | ||
} | ||
|
||
// put appends peer ID and message data and stores it in cache with TTL. | ||
func (m *messageCache) put(peer peer.ID, msg NotificationsMessage) (bool, error) { | ||
key, err := generateCacheKey(peer, msg) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
_, ok := m.cache.Get(key) | ||
if ok { | ||
return false, nil | ||
} | ||
|
||
ok = m.cache.SetWithTTL(key, "", 1, m.ttl) | ||
return ok, nil | ||
} | ||
|
||
// exists checks if <peer ID, message> exist in cache. | ||
func (m *messageCache) exists(peer peer.ID, msg NotificationsMessage) bool { | ||
key, err := generateCacheKey(peer, msg) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
_, ok := m.cache.Get(key) | ||
return ok | ||
} | ||
|
||
func generateCacheKey(peer peer.ID, msg NotificationsMessage) ([]byte, error) { | ||
if msg.IsHandshake() { | ||
return nil, errors.New("cache does not support handshake messages") | ||
} | ||
|
||
peerMsgHash, err := common.Blake2bHash(append([]byte(peer), msg.Hash().ToBytes()...)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return peerMsgHash.ToBytes(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package network | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
"time" | ||
|
||
"github.com/ChainSafe/gossamer/dot/types" | ||
"github.com/ChainSafe/gossamer/lib/common" | ||
"github.com/dgraph-io/ristretto" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestMessageCache(t *testing.T) { | ||
cacheSize := 64 << 20 // 64 MB | ||
msgCache, err := newMessageCache(ristretto.Config{ | ||
NumCounters: int64(float64(cacheSize) * 0.05 * 2), | ||
MaxCost: int64(float64(cacheSize) * 0.95), | ||
BufferItems: 64, | ||
Cost: func(value interface{}) int64 { | ||
return int64(1) | ||
}, | ||
}, 800*time.Millisecond) | ||
require.NoError(t, err) | ||
|
||
peerID := peer.ID("gossamer") | ||
msg := &BlockAnnounceMessage{ | ||
ParentHash: common.Hash{1}, | ||
Number: big.NewInt(77), | ||
StateRoot: common.Hash{2}, | ||
ExtrinsicsRoot: common.Hash{3}, | ||
Digest: types.Digest{}, | ||
} | ||
|
||
ok, err := msgCache.put(peerID, msg) | ||
require.NoError(t, err) | ||
require.True(t, ok) | ||
|
||
time.Sleep(750 * time.Millisecond) | ||
|
||
ok = msgCache.exists(peerID, msg) | ||
require.True(t, ok) | ||
|
||
time.Sleep(50 * time.Millisecond) | ||
|
||
ok = msgCache.exists(peerID, msg) | ||
require.False(t, ok) | ||
} | ||
|
||
func TestMessageCacheError(t *testing.T) { | ||
cacheSize := 64 << 20 // 64 MB | ||
msgCache, err := newMessageCache(ristretto.Config{ | ||
NumCounters: int64(float64(cacheSize) * 0.05 * 2), | ||
MaxCost: int64(float64(cacheSize) * 0.95), | ||
BufferItems: 64, | ||
Cost: func(value interface{}) int64 { | ||
return int64(1) | ||
}, | ||
}, 800*time.Millisecond) | ||
require.NoError(t, err) | ||
|
||
peerID := peer.ID("gossamer") | ||
msg := &BlockAnnounceHandshake{ | ||
Roles: 4, | ||
BestBlockNumber: 77, | ||
BestBlockHash: common.Hash{1}, | ||
GenesisHash: common.Hash{2}, | ||
} | ||
|
||
ok, err := msgCache.put(peerID, msg) | ||
require.Error(t, err, "cache does not support handshake messages") | ||
require.False(t, ok) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters