Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
7de5042c
Unverified
Commit
7de5042c
authored
May 30, 2023
by
Adrian Sutton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-node: Add a histogram to report current peer scores
parent
6a474e36
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
179 additions
and
90 deletions
+179
-90
histogram_snapshot.go
op-node/metrics/histogram_snapshot.go
+44
-0
metrics.go
op-node/metrics/metrics.go
+32
-12
GossipMetricer.go
op-node/p2p/mocks/GossipMetricer.go
+1
-6
Peerstore.go
op-node/p2p/mocks/Peerstore.go
+15
-5
ScoreMetrics.go
op-node/p2p/mocks/ScoreMetrics.go
+34
-0
peer_scorer.go
op-node/p2p/peer_scorer.go
+8
-4
peer_scorer_test.go
op-node/p2p/peer_scorer_test.go
+7
-36
peer_scores_test.go
op-node/p2p/peer_scores_test.go
+3
-3
iface.go
op-node/p2p/store/iface.go
+1
-1
ip_ban_book.go
op-node/p2p/store/ip_ban_book.go
+2
-1
peer_ban_book.go
op-node/p2p/store/peer_ban_book.go
+2
-1
records_book.go
op-node/p2p/store/records_book.go
+5
-5
scorebook.go
op-node/p2p/store/scorebook.go
+3
-2
scorebook_test.go
op-node/p2p/store/scorebook_test.go
+22
-14
No files found.
op-node/metrics/histogram_snapshot.go
0 → 100644
View file @
7de5042c
package
metrics
import
(
"sync/atomic"
"github.com/prometheus/client_golang/prometheus"
)
type
ReplaceableHistogramVec
struct
{
current
*
atomic
.
Value
opts
prometheus
.
HistogramOpts
variableLabels
[]
string
}
func
NewReplaceableHistogramVec
(
registry
*
prometheus
.
Registry
,
opts
prometheus
.
HistogramOpts
,
variableLabels
[]
string
)
*
ReplaceableHistogramVec
{
metric
:=
&
ReplaceableHistogramVec
{
current
:
&
atomic
.
Value
{},
opts
:
opts
,
variableLabels
:
variableLabels
,
}
metric
.
current
.
Store
(
prometheus
.
NewHistogramVec
(
opts
,
variableLabels
))
registry
.
MustRegister
(
metric
)
return
metric
}
func
(
c
*
ReplaceableHistogramVec
)
Replace
(
updater
func
(
h
*
prometheus
.
HistogramVec
))
{
h
:=
prometheus
.
NewHistogramVec
(
c
.
opts
,
c
.
variableLabels
)
updater
(
h
)
c
.
current
.
Store
(
h
)
}
func
(
c
*
ReplaceableHistogramVec
)
Describe
(
ch
chan
<-
*
prometheus
.
Desc
)
{
collector
,
ok
:=
c
.
current
.
Load
()
.
(
prometheus
.
Collector
)
if
ok
{
collector
.
Describe
(
ch
)
}
}
func
(
c
*
ReplaceableHistogramVec
)
Collect
(
ch
chan
<-
prometheus
.
Metric
)
{
collector
,
ok
:=
c
.
current
.
Load
()
.
(
prometheus
.
Collector
)
if
ok
{
collector
.
Collect
(
ch
)
}
}
op-node/metrics/metrics.go
View file @
7de5042c
...
...
@@ -11,6 +11,7 @@ import (
"time"
ophttp
"github.com/ethereum-optimism/optimism/op-node/http"
"github.com/ethereum-optimism/optimism/op-node/p2p/store"
"github.com/ethereum-optimism/optimism/op-service/metrics"
pb
"github.com/libp2p/go-libp2p-pubsub/pb"
...
...
@@ -66,7 +67,7 @@ type Metricer interface {
Document
()
[]
metrics
.
DocumentedMetric
RecordChannelInputBytes
(
num
int
)
// P2P Metrics
SetPeerScores
(
scores
map
[
string
]
float64
)
SetPeerScores
(
scores
map
[
string
]
float64
,
allScores
[]
store
.
PeerScores
)
ClientPayloadByNumberEvent
(
num
uint64
,
resultCode
byte
,
duration
time
.
Duration
)
ServerPayloadByNumberEvent
(
num
uint64
,
resultCode
byte
,
duration
time
.
Duration
)
PayloadsQuarantineSize
(
n
int
)
...
...
@@ -141,6 +142,7 @@ type Metrics struct {
IPUnbans
prometheus
.
Counter
Dials
*
prometheus
.
CounterVec
Accepts
*
prometheus
.
CounterVec
PeerScoresHistogram
*
ReplaceableHistogramVec
ChannelInputBytes
prometheus
.
Counter
...
...
@@ -161,6 +163,7 @@ func NewMetrics(procName string) *Metrics {
registry
.
MustRegister
(
collectors
.
NewProcessCollector
(
collectors
.
ProcessCollectorOpts
{}))
registry
.
MustRegister
(
collectors
.
NewGoCollector
())
factory
:=
metrics
.
With
(
registry
)
return
&
Metrics
{
Info
:
factory
.
NewGaugeVec
(
prometheus
.
GaugeOpts
{
Namespace
:
ns
,
...
...
@@ -321,6 +324,12 @@ func NewMetrics(procName string) *Metrics {
},
[]
string
{
"band"
,
}),
PeerScoresHistogram
:
NewReplaceableHistogramVec
(
registry
,
prometheus
.
HistogramOpts
{
Namespace
:
ns
,
Name
:
"peer_scores_histogram"
,
Help
:
"Histogram of currrently connected peer scores"
,
Buckets
:
[]
float64
{
-
100
,
-
40
,
-
20
,
-
10
,
-
5
,
-
2
,
-
1
,
-
0.5
,
-
0.05
,
0
,
0.05
,
0.5
,
1
,
2
,
5
,
10
,
20
,
40
},
},
[]
string
{
"type"
}),
StreamCount
:
factory
.
NewGauge
(
prometheus
.
GaugeOpts
{
Namespace
:
ns
,
Subsystem
:
"p2p"
,
...
...
@@ -452,7 +461,18 @@ func NewMetrics(procName string) *Metrics {
// SetPeerScores updates the peer score [prometheus.GaugeVec].
// This takes a map of labels to scores.
func
(
m
*
Metrics
)
SetPeerScores
(
scores
map
[
string
]
float64
)
{
func
(
m
*
Metrics
)
SetPeerScores
(
scores
map
[
string
]
float64
,
allScores
[]
store
.
PeerScores
)
{
m
.
PeerScoresHistogram
.
Replace
(
func
(
h
*
prometheus
.
HistogramVec
)
{
for
_
,
scores
:=
range
allScores
{
h
.
WithLabelValues
(
"total"
)
.
Observe
(
scores
.
Gossip
.
Total
)
h
.
WithLabelValues
(
"ipColocation"
)
.
Observe
(
scores
.
Gossip
.
IPColocationFactor
)
h
.
WithLabelValues
(
"behavioralPenalty"
)
.
Observe
(
scores
.
Gossip
.
BehavioralPenalty
)
h
.
WithLabelValues
(
"blocksFirstMessage"
)
.
Observe
(
scores
.
Gossip
.
Blocks
.
FirstMessageDeliveries
)
h
.
WithLabelValues
(
"blocksTimeInMesh"
)
.
Observe
(
scores
.
Gossip
.
Blocks
.
TimeInMesh
)
h
.
WithLabelValues
(
"blocksMessageDeliveries"
)
.
Observe
(
scores
.
Gossip
.
Blocks
.
MeshMessageDeliveries
)
h
.
WithLabelValues
(
"blocksInvalidMessageDeliveries"
)
.
Observe
(
scores
.
Gossip
.
Blocks
.
InvalidMessageDeliveries
)
}
})
for
label
,
score
:=
range
scores
{
m
.
PeerScores
.
WithLabelValues
(
label
)
.
Set
(
score
)
}
...
...
@@ -785,7 +805,7 @@ func (n *noopMetricer) RecordSequencerReset() {
func
(
n
*
noopMetricer
)
RecordGossipEvent
(
evType
int32
)
{
}
func
(
n
*
noopMetricer
)
SetPeerScores
(
scores
map
[
string
]
float64
)
{
func
(
n
*
noopMetricer
)
SetPeerScores
(
scores
map
[
string
]
float64
,
allScores
[]
store
.
PeerScores
)
{
}
func
(
n
*
noopMetricer
)
IncPeerCount
()
{
...
...
op-node/p2p/mocks/GossipMetricer.go
View file @
7de5042c
// Code generated by mockery v2.2
2.1
. DO NOT EDIT.
// Code generated by mockery v2.2
8.0
. DO NOT EDIT.
package
mocks
...
...
@@ -14,11 +14,6 @@ func (_m *GossipMetricer) RecordGossipEvent(evType int32) {
_m
.
Called
(
evType
)
}
// SetPeerScores provides a mock function with given fields: _a0
func
(
_m
*
GossipMetricer
)
SetPeerScores
(
_a0
map
[
string
]
float64
)
{
_m
.
Called
(
_a0
)
}
type
mockConstructorTestingTNewGossipMetricer
interface
{
mock
.
TestingT
Cleanup
(
func
())
...
...
op-node/p2p/mocks/Peerstore.go
View file @
7de5042c
...
...
@@ -46,17 +46,27 @@ func (_m *Peerstore) Peers() peer.IDSlice {
}
// SetScore provides a mock function with given fields: id, diff
func
(
_m
*
Peerstore
)
SetScore
(
id
peer
.
ID
,
diff
store
.
ScoreDiff
)
error
{
func
(
_m
*
Peerstore
)
SetScore
(
id
peer
.
ID
,
diff
store
.
ScoreDiff
)
(
store
.
PeerScores
,
error
)
{
ret
:=
_m
.
Called
(
id
,
diff
)
var
r0
error
if
rf
,
ok
:=
ret
.
Get
(
0
)
.
(
func
(
peer
.
ID
,
store
.
ScoreDiff
)
error
);
ok
{
var
r0
store
.
PeerScores
var
r1
error
if
rf
,
ok
:=
ret
.
Get
(
0
)
.
(
func
(
peer
.
ID
,
store
.
ScoreDiff
)
(
store
.
PeerScores
,
error
));
ok
{
return
rf
(
id
,
diff
)
}
if
rf
,
ok
:=
ret
.
Get
(
0
)
.
(
func
(
peer
.
ID
,
store
.
ScoreDiff
)
store
.
PeerScores
);
ok
{
r0
=
rf
(
id
,
diff
)
}
else
{
r0
=
ret
.
Error
(
0
)
r0
=
ret
.
Get
(
0
)
.
(
store
.
PeerScores
)
}
return
r0
if
rf
,
ok
:=
ret
.
Get
(
1
)
.
(
func
(
peer
.
ID
,
store
.
ScoreDiff
)
error
);
ok
{
r1
=
rf
(
id
,
diff
)
}
else
{
r1
=
ret
.
Error
(
1
)
}
return
r0
,
r1
}
type
mockConstructorTestingTNewPeerstore
interface
{
...
...
op-node/p2p/mocks/ScoreMetrics.go
0 → 100644
View file @
7de5042c
// Code generated by mockery v2.28.0. DO NOT EDIT.
package
mocks
import
(
mock
"github.com/stretchr/testify/mock"
store
"github.com/ethereum-optimism/optimism/op-node/p2p/store"
)
// ScoreMetrics is an autogenerated mock type for the ScoreMetrics type
type
ScoreMetrics
struct
{
mock
.
Mock
}
// SetPeerScores provides a mock function with given fields: _a0, _a1
func
(
_m
*
ScoreMetrics
)
SetPeerScores
(
_a0
map
[
string
]
float64
,
_a1
[]
store
.
PeerScores
)
{
_m
.
Called
(
_a0
,
_a1
)
}
type
mockConstructorTestingTNewScoreMetrics
interface
{
mock
.
TestingT
Cleanup
(
func
())
}
// NewScoreMetrics creates a new instance of ScoreMetrics. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func
NewScoreMetrics
(
t
mockConstructorTestingTNewScoreMetrics
)
*
ScoreMetrics
{
mock
:=
&
ScoreMetrics
{}
mock
.
Mock
.
Test
(
t
)
t
.
Cleanup
(
func
()
{
mock
.
AssertExpectations
(
t
)
})
return
mock
}
op-node/p2p/peer_scorer.go
View file @
7de5042c
...
...
@@ -96,7 +96,7 @@ type Peerstore interface {
// Peers returns all of the peer IDs stored across all inner stores.
Peers
()
peer
.
IDSlice
SetScore
(
id
peer
.
ID
,
diff
store
.
ScoreDiff
)
error
SetScore
(
id
peer
.
ID
,
diff
store
.
ScoreDiff
)
(
store
.
PeerScores
,
error
)
}
// Scorer is a peer scorer that scores peers based on application-specific metrics.
...
...
@@ -106,8 +106,9 @@ type Scorer interface {
SnapshotHook
()
pubsub
.
ExtendedPeerScoreInspectFn
}
//go:generate mockery --name ScoreMetrics --output mocks/
type
ScoreMetrics
interface
{
SetPeerScores
(
map
[
string
]
float64
)
SetPeerScores
(
map
[
string
]
float64
,
[]
store
.
PeerScores
)
}
// NewScorer returns a new peer scorer.
...
...
@@ -129,6 +130,7 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
blocksTopicName
:=
blocksTopicV1
(
s
.
cfg
)
return
func
(
m
map
[
peer
.
ID
]
*
pubsub
.
PeerScoreSnapshot
)
{
scoreMap
:=
make
(
map
[
string
]
float64
)
allScores
:=
make
([]
store
.
PeerScores
,
0
,
len
(
m
))
// Zero out all bands.
for
_
,
b
:=
range
s
.
bandScoreThresholds
.
bands
{
scoreMap
[
b
.
band
]
=
0
...
...
@@ -147,15 +149,17 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
diff
.
Blocks
.
FirstMessageDeliveries
=
topSnap
.
FirstMessageDeliveries
diff
.
Blocks
.
InvalidMessageDeliveries
=
topSnap
.
InvalidMessageDeliveries
}
if
err
:=
s
.
peerStore
.
SetScore
(
id
,
&
diff
);
err
!=
nil
{
if
peerScores
,
err
:=
s
.
peerStore
.
SetScore
(
id
,
&
diff
);
err
!=
nil
{
s
.
log
.
Warn
(
"Unable to update peer gossip score"
,
"err"
,
err
)
}
else
{
allScores
=
append
(
allScores
,
peerScores
)
}
}
for
_
,
snap
:=
range
m
{
band
:=
s
.
bandScoreThresholds
.
Bucket
(
snap
.
Score
)
scoreMap
[
band
]
+=
1
}
s
.
metricer
.
SetPeerScores
(
scoreMap
)
s
.
metricer
.
SetPeerScores
(
scoreMap
,
allScores
)
}
}
...
...
op-node/p2p/peer_scorer_test.go
View file @
7de5042c
...
...
@@ -22,7 +22,7 @@ type PeerScorerTestSuite struct {
suite
.
Suite
mockStore
*
p2pMocks
.
Peerstore
mockMetricer
*
p2pMocks
.
GossipMetricer
mockMetricer
*
p2pMocks
.
ScoreMetrics
bandScorer
*
p2p
.
BandScoreThresholds
logger
log
.
Logger
}
...
...
@@ -30,7 +30,7 @@ type PeerScorerTestSuite struct {
// SetupTest sets up the test suite.
func
(
testSuite
*
PeerScorerTestSuite
)
SetupTest
()
{
testSuite
.
mockStore
=
&
p2pMocks
.
Peerstore
{}
testSuite
.
mockMetricer
=
&
p2pMocks
.
GossipMetricer
{}
testSuite
.
mockMetricer
=
&
p2pMocks
.
ScoreMetrics
{}
bandScorer
,
err
:=
p2p
.
NewBandScorer
(
"-40:graylist;0:friend;"
)
testSuite
.
NoError
(
err
)
testSuite
.
bandScorer
=
bandScorer
...
...
@@ -77,14 +77,15 @@ func (testSuite *PeerScorerTestSuite) TestScorer_SnapshotHook() {
)
inspectFn
:=
scorer
.
SnapshotHook
()
scores
:=
store
.
PeerScores
{}
// Expect updating the peer store
testSuite
.
mockStore
.
On
(
"SetScore"
,
peer
.
ID
(
"peer1"
),
&
store
.
GossipScores
{
Total
:
float64
(
-
100
)})
.
Return
(
nil
)
.
Once
()
testSuite
.
mockStore
.
On
(
"SetScore"
,
peer
.
ID
(
"peer1"
),
&
store
.
GossipScores
{
Total
:
float64
(
-
100
)})
.
Return
(
scores
,
nil
)
.
Once
()
// The metricer should then be called with the peer score band map
testSuite
.
mockMetricer
.
On
(
"SetPeerScores"
,
map
[
string
]
float64
{
"friend"
:
0
,
"graylist"
:
1
,
})
.
Return
(
nil
)
.
Once
()
}
,
[]
store
.
PeerScores
{
scores
}
)
.
Return
(
nil
)
.
Once
()
// Apply the snapshot
snapshotMap
:=
map
[
peer
.
ID
]
*
pubsub
.
PeerScoreSnapshot
{
...
...
@@ -95,13 +96,13 @@ func (testSuite *PeerScorerTestSuite) TestScorer_SnapshotHook() {
inspectFn
(
snapshotMap
)
// Expect updating the peer store
testSuite
.
mockStore
.
On
(
"SetScore"
,
peer
.
ID
(
"peer1"
),
&
store
.
GossipScores
{
Total
:
0
})
.
Return
(
nil
)
.
Once
()
testSuite
.
mockStore
.
On
(
"SetScore"
,
peer
.
ID
(
"peer1"
),
&
store
.
GossipScores
{
Total
:
0
})
.
Return
(
scores
,
nil
)
.
Once
()
// The metricer should then be called with the peer score band map
testSuite
.
mockMetricer
.
On
(
"SetPeerScores"
,
map
[
string
]
float64
{
"friend"
:
1
,
"graylist"
:
0
,
})
.
Return
(
nil
)
.
Once
()
}
,
[]
store
.
PeerScores
{
scores
}
)
.
Return
(
nil
)
.
Once
()
// Apply the snapshot
snapshotMap
=
map
[
peer
.
ID
]
*
pubsub
.
PeerScoreSnapshot
{
...
...
@@ -111,33 +112,3 @@ func (testSuite *PeerScorerTestSuite) TestScorer_SnapshotHook() {
}
inspectFn
(
snapshotMap
)
}
// TestScorer_SnapshotHookBlocksPeer tests running the snapshot hook on the peer scorer with a peer score below the threshold.
// This implies that the peer should be blocked.
func
(
testSuite
*
PeerScorerTestSuite
)
TestScorer_SnapshotHookBlocksPeer
()
{
scorer
:=
p2p
.
NewScorer
(
&
rollup
.
Config
{
L2ChainID
:
big
.
NewInt
(
123
)},
testSuite
.
mockStore
,
testSuite
.
mockMetricer
,
testSuite
.
bandScorer
,
testSuite
.
logger
,
)
inspectFn
:=
scorer
.
SnapshotHook
()
// Expect updating the peer store
testSuite
.
mockStore
.
On
(
"SetScore"
,
peer
.
ID
(
"peer1"
),
&
store
.
GossipScores
{
Total
:
float64
(
-
101
)})
.
Return
(
nil
)
.
Once
()
// The metricer should then be called with the peer score band map
testSuite
.
mockMetricer
.
On
(
"SetPeerScores"
,
map
[
string
]
float64
{
"friend"
:
0
,
"graylist"
:
1
,
})
.
Return
(
nil
)
// Apply the snapshot
snapshotMap
:=
map
[
peer
.
ID
]
*
pubsub
.
PeerScoreSnapshot
{
peer
.
ID
(
"peer1"
)
:
{
Score
:
-
101
,
},
}
inspectFn
(
snapshotMap
)
}
op-node/p2p/peer_scores_test.go
View file @
7de5042c
...
...
@@ -36,7 +36,7 @@ type PeerScoresTestSuite struct {
suite
.
Suite
mockStore
*
p2pMocks
.
Peerstore
mockMetricer
*
p2pMocks
.
GossipMetricer
mockMetricer
*
p2pMocks
.
ScoreMetrics
bandScorer
BandScoreThresholds
logger
log
.
Logger
}
...
...
@@ -44,7 +44,7 @@ type PeerScoresTestSuite struct {
// SetupTest sets up the test suite.
func
(
testSuite
*
PeerScoresTestSuite
)
SetupTest
()
{
testSuite
.
mockStore
=
&
p2pMocks
.
Peerstore
{}
testSuite
.
mockMetricer
=
&
p2pMocks
.
GossipMetricer
{}
testSuite
.
mockMetricer
=
&
p2pMocks
.
ScoreMetrics
{}
bandScorer
,
err
:=
NewBandScorer
(
"0:graylist;"
)
testSuite
.
NoError
(
err
)
testSuite
.
bandScorer
=
*
bandScorer
...
...
@@ -157,7 +157,7 @@ func (testSuite *PeerScoresTestSuite) TestNegativeScores() {
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
testSuite
.
mockMetricer
.
On
(
"SetPeerScores"
,
mock
.
Anything
)
.
Return
(
nil
)
testSuite
.
mockMetricer
.
On
(
"SetPeerScores"
,
mock
.
Anything
,
mock
.
Anything
)
.
Return
(
nil
)
// Construct 20 hosts using the [getNetHosts] function.
hosts
:=
getNetHosts
(
testSuite
,
ctx
,
20
)
...
...
op-node/p2p/store/iface.go
View file @
7de5042c
...
...
@@ -41,7 +41,7 @@ type ScoreDatastore interface {
GetPeerScore
(
id
peer
.
ID
)
(
float64
,
error
)
// SetScore applies the given store diff to the specified peer
SetScore
(
id
peer
.
ID
,
diff
ScoreDiff
)
error
SetScore
(
id
peer
.
ID
,
diff
ScoreDiff
)
(
PeerScores
,
error
)
}
// ScoreDiff defines a type-safe batch of changes to apply to the peer-scoring record of the peer.
...
...
op-node/p2p/store/ip_ban_book.go
View file @
7de5042c
...
...
@@ -84,7 +84,8 @@ func (d *ipBanBook) SetIPBanExpiration(ip net.IP, expirationTime time.Time) erro
if
expirationTime
==
(
time
.
Time
{})
{
return
d
.
book
.
deleteRecord
(
ip
.
To16
()
.
String
())
}
return
d
.
book
.
SetRecord
(
ip
.
To16
()
.
String
(),
ipBanUpdate
(
expirationTime
))
_
,
err
:=
d
.
book
.
SetRecord
(
ip
.
To16
()
.
String
(),
ipBanUpdate
(
expirationTime
))
return
err
}
func
(
d
*
ipBanBook
)
Close
()
{
...
...
op-node/p2p/store/peer_ban_book.go
View file @
7de5042c
...
...
@@ -80,7 +80,8 @@ func (d *peerBanBook) SetPeerBanExpiration(id peer.ID, expirationTime time.Time)
if
expirationTime
==
(
time
.
Time
{})
{
return
d
.
book
.
deleteRecord
(
id
)
}
return
d
.
book
.
SetRecord
(
id
,
peerBanUpdate
(
expirationTime
))
_
,
err
:=
d
.
book
.
SetRecord
(
id
,
peerBanUpdate
(
expirationTime
))
return
err
}
func
(
d
*
peerBanBook
)
Close
()
{
...
...
op-node/p2p/store/records_book.go
View file @
7de5042c
...
...
@@ -124,27 +124,27 @@ func (d *recordsBook[K, V]) getRecord(key K) (v V, err error) {
return
v
,
nil
}
func
(
d
*
recordsBook
[
K
,
V
])
SetRecord
(
key
K
,
diff
recordDiff
[
V
])
error
{
func
(
d
*
recordsBook
[
K
,
V
])
SetRecord
(
key
K
,
diff
recordDiff
[
V
])
(
V
,
error
)
{
d
.
Lock
()
defer
d
.
Unlock
()
rec
,
err
:=
d
.
getRecord
(
key
)
if
err
==
UnknownRecordErr
{
// instantiate new record if it does not exist yet
rec
=
d
.
newRecord
()
}
else
if
err
!=
nil
{
return
err
return
d
.
newRecord
(),
err
}
rec
.
SetLastUpdated
(
d
.
clock
.
Now
())
diff
.
Apply
(
rec
)
data
,
err
:=
rec
.
MarshalBinary
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to encode record for key %v: %w"
,
key
,
err
)
return
d
.
newRecord
(),
fmt
.
Errorf
(
"failed to encode record for key %v: %w"
,
key
,
err
)
}
err
=
d
.
store
.
Put
(
d
.
ctx
,
d
.
dsKey
(
key
),
data
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"storing updated record for key %v: %w"
,
key
,
err
)
return
d
.
newRecord
(),
fmt
.
Errorf
(
"storing updated record for key %v: %w"
,
key
,
err
)
}
d
.
cache
.
Add
(
key
,
rec
)
return
nil
return
rec
,
nil
}
// prune deletes entries from the store that are older than the configured prune expiration.
...
...
op-node/p2p/store/scorebook.go
View file @
7de5042c
...
...
@@ -86,8 +86,9 @@ func (d *scoreBook) GetPeerScore(id peer.ID) (float64, error) {
return
scores
.
Gossip
.
Total
,
nil
}
func
(
d
*
scoreBook
)
SetScore
(
id
peer
.
ID
,
diff
ScoreDiff
)
error
{
return
d
.
book
.
SetRecord
(
id
,
diff
)
func
(
d
*
scoreBook
)
SetScore
(
id
peer
.
ID
,
diff
ScoreDiff
)
(
PeerScores
,
error
)
{
v
,
err
:=
d
.
book
.
SetRecord
(
id
,
diff
)
return
v
.
PeerScores
,
err
}
func
(
d
*
scoreBook
)
Close
()
{
...
...
op-node/p2p/store/scorebook_test.go
View file @
7de5042c
...
...
@@ -26,18 +26,21 @@ func TestRoundTripGossipScore(t *testing.T) {
id
:=
peer
.
ID
(
"aaaa"
)
store
:=
createMemoryStore
(
t
)
score
:=
123.45
err
:=
store
.
SetScore
(
id
,
&
GossipScores
{
Total
:
score
})
res
,
err
:=
store
.
SetScore
(
id
,
&
GossipScores
{
Total
:
score
})
require
.
NoError
(
t
,
err
)
assertPeerScores
(
t
,
store
,
id
,
PeerScores
{
Gossip
:
GossipScores
{
Total
:
score
}})
expected
:=
PeerScores
{
Gossip
:
GossipScores
{
Total
:
score
}}
require
.
Equal
(
t
,
expected
,
res
)
assertPeerScores
(
t
,
store
,
id
,
expected
)
}
func
TestUpdateGossipScore
(
t
*
testing
.
T
)
{
id
:=
peer
.
ID
(
"aaaa"
)
store
:=
createMemoryStore
(
t
)
score
:=
123.45
require
.
NoError
(
t
,
store
.
SetScore
(
id
,
&
GossipScores
{
Total
:
444.223
})
)
require
.
NoError
(
t
,
store
.
SetScore
(
id
,
&
GossipScores
{
Total
:
score
})
)
setScoreRequired
(
t
,
store
,
id
,
&
GossipScores
{
Total
:
444.223
}
)
setScoreRequired
(
t
,
store
,
id
,
&
GossipScores
{
Total
:
score
}
)
assertPeerScores
(
t
,
store
,
id
,
PeerScores
{
Gossip
:
GossipScores
{
Total
:
score
}})
}
...
...
@@ -48,8 +51,8 @@ func TestStoreScoresForMultiplePeers(t *testing.T) {
store
:=
createMemoryStore
(
t
)
score1
:=
123.45
score2
:=
453.22
require
.
NoError
(
t
,
store
.
SetScore
(
id1
,
&
GossipScores
{
Total
:
score1
})
)
require
.
NoError
(
t
,
store
.
SetScore
(
id2
,
&
GossipScores
{
Total
:
score2
})
)
setScoreRequired
(
t
,
store
,
id1
,
&
GossipScores
{
Total
:
score1
}
)
setScoreRequired
(
t
,
store
,
id2
,
&
GossipScores
{
Total
:
score2
}
)
assertPeerScores
(
t
,
store
,
id1
,
PeerScores
{
Gossip
:
GossipScores
{
Total
:
score1
}})
assertPeerScores
(
t
,
store
,
id2
,
PeerScores
{
Gossip
:
GossipScores
{
Total
:
score2
}})
...
...
@@ -61,7 +64,7 @@ func TestPersistData(t *testing.T) {
backingStore
:=
sync
.
MutexWrap
(
ds
.
NewMapDatastore
())
store
:=
createPeerstoreWithBacking
(
t
,
backingStore
)
require
.
NoError
(
t
,
store
.
SetScore
(
id
,
&
GossipScores
{
Total
:
score
})
)
setScoreRequired
(
t
,
store
,
id
,
&
GossipScores
{
Total
:
score
}
)
// Close and recreate a new store from the same backing
require
.
NoError
(
t
,
store
.
Close
())
...
...
@@ -92,17 +95,17 @@ func TestPrune(t *testing.T) {
firstStore
:=
clock
.
Now
()
// Set some scores all 30 minutes apart so they have different expiry times
require
.
NoError
(
t
,
book
.
SetScore
(
"aaaa"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"aaaa"
,
&
GossipScores
{
Total
:
123.45
}
)
clock
.
AdvanceTime
(
30
*
time
.
Minute
)
require
.
NoError
(
t
,
book
.
SetScore
(
"bbbb"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"bbbb"
,
&
GossipScores
{
Total
:
123.45
}
)
clock
.
AdvanceTime
(
30
*
time
.
Minute
)
require
.
NoError
(
t
,
book
.
SetScore
(
"cccc"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"cccc"
,
&
GossipScores
{
Total
:
123.45
}
)
clock
.
AdvanceTime
(
30
*
time
.
Minute
)
require
.
NoError
(
t
,
book
.
SetScore
(
"dddd"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"dddd"
,
&
GossipScores
{
Total
:
123.45
}
)
clock
.
AdvanceTime
(
30
*
time
.
Minute
)
// Update bbbb again which should extend its expiry
require
.
NoError
(
t
,
book
.
SetScore
(
"bbbb"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"bbbb"
,
&
GossipScores
{
Total
:
123.45
}
)
require
.
True
(
t
,
hasScoreRecorded
(
"aaaa"
))
require
.
True
(
t
,
hasScoreRecorded
(
"bbbb"
))
...
...
@@ -147,7 +150,7 @@ func TestPruneMultipleBatches(t *testing.T) {
// Set scores for more peers than the max batch size
peerCount
:=
maxPruneBatchSize
*
3
+
5
for
i
:=
0
;
i
<
peerCount
;
i
++
{
require
.
NoError
(
t
,
book
.
SetScore
(
peer
.
ID
(
strconv
.
Itoa
(
i
)),
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
peer
.
ID
(
strconv
.
Itoa
(
i
)),
&
GossipScores
{
Total
:
123.45
}
)
}
clock
.
AdvanceTime
(
book
.
book
.
recordExpiry
+
1
)
require
.
NoError
(
t
,
book
.
book
.
prune
())
...
...
@@ -169,7 +172,7 @@ func TestIgnoreOutdatedScores(t *testing.T) {
book
,
err
:=
newScoreBook
(
ctx
,
logger
,
clock
,
sync
.
MutexWrap
(
ds
.
NewMapDatastore
()),
retentionPeriod
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
book
.
SetScore
(
"a"
,
&
GossipScores
{
Total
:
123.45
})
)
setScoreRequired
(
t
,
book
,
"a"
,
&
GossipScores
{
Total
:
123.45
}
)
clock
.
AdvanceTime
(
retentionPeriod
+
1
)
// Not available from cache
...
...
@@ -211,3 +214,8 @@ func createPeerstoreWithBacking(t *testing.T, store *sync.MutexDatastore) Extend
})
return
eps
}
func
setScoreRequired
(
t
*
testing
.
T
,
store
ScoreDatastore
,
id
peer
.
ID
,
diff
*
GossipScores
)
{
_
,
err
:=
store
.
SetScore
(
id
,
diff
)
require
.
NoError
(
t
,
err
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment