github.com/anacrolix/utp v0.1.0
github.com/bahlo/generic-list-go v0.2.0
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8
+ github.com/cespare/xxhash v1.1.0
github.com/davecgh/go-spew v1.1.1
github.com/dustin/go-humanize v1.0.0
github.com/edsrzf/mmap-go v1.1.0
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
package smartban
import (
+ g "github.com/anacrolix/generics"
"sync"
)
Hash func([]byte) Hash
lock sync.RWMutex
- blocks map[BlockKey]map[Peer]Hash
+ blocks map[BlockKey][]peerAndHash[Peer, Hash]
}
type Block[Key any] struct {
Data []byte
}
+type peerAndHash[Peer, Hash any] struct {
+ Peer Peer
+ Hash Hash
+}
+
func (me *Cache[Peer, BlockKey, Hash]) Init() {
- me.blocks = make(map[BlockKey]map[Peer]Hash)
+ g.MakeMap(&me.blocks)
}
func (me *Cache[Peer, BlockKey, Hash]) RecordBlock(peer Peer, key BlockKey, data []byte) {
me.lock.Lock()
defer me.lock.Unlock()
peers := me.blocks[key]
- if peers == nil {
- peers = make(map[Peer]Hash)
- me.blocks[key] = peers
- }
- peers[peer] = hash
+ peers = append(peers, peerAndHash[Peer, Hash]{peer, hash})
+ me.blocks[key] = peers
}
func (me *Cache[Peer, BlockKey, Hash]) CheckBlock(key BlockKey, data []byte) (bad []Peer) {
correct := me.Hash(data)
me.lock.RLock()
defer me.lock.RUnlock()
- for peer, hash := range me.blocks[key] {
- if hash != correct {
- bad = append(bad, peer)
+ for _, item := range me.blocks[key] {
+ if item.Hash != correct {
+ bad = append(bad, item.Peer)
}
}
return
--- /dev/null
+package torrent
+
+import (
+ "crypto/sha1"
+ "github.com/anacrolix/missinggo/v2/iter"
+ "github.com/anacrolix/torrent/smartban"
+ "github.com/cespare/xxhash"
+ "net/netip"
+ "testing"
+)
+
+func benchmarkSmartBanRecordBlock[Sum comparable](b *testing.B, hash func([]byte) Sum) {
+ var cache smartban.Cache[bannableAddr, RequestIndex, Sum]
+ cache.Hash = hash
+ cache.Init()
+ var data [defaultChunkSize]byte
+ var addr netip.Addr
+ b.SetBytes(int64(len(data)))
+ for i := range iter.N(b.N) {
+ cache.RecordBlock(addr, RequestIndex(i), data[:])
+ }
+}
+
+func BenchmarkSmartBanRecordBlock(b *testing.B) {
+ b.Run("xxHash", func(b *testing.B) {
+ var salt [8]byte
+ benchmarkSmartBanRecordBlock(b, func(block []byte) uint64 {
+ h := xxhash.New()
+ // xxHash is not cryptographic, and so we're salting it so attackers can't know a priori
+ // where block data collisions are.
+ h.Write(salt[:])
+ h.Write(block)
+ return h.Sum64()
+ })
+ })
+ b.Run("Sha1", func(b *testing.B) {
+ benchmarkSmartBanRecordBlock(b, sha1.Sum)
+ })
+}