github.com/amazechain/amc@v0.1.3/internal/p2p/gossip_scoring_params.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 "strings" 8 "time" 9 10 pubsub "github.com/libp2p/go-libp2p-pubsub" 11 "github.com/libp2p/go-libp2p/core/peer" 12 "github.com/pkg/errors" 13 ) 14 15 const ( 16 // beaconBlockWeight specifies the scoring weight that we apply to 17 // our beacon block topic. 18 beaconBlockWeight = 0.8 19 // aggregateWeight specifies the scoring weight that we apply to 20 // our aggregate topic. 21 aggregateWeight = 0.5 22 // syncContributionWeight specifies the scoring weight that we apply to 23 // our sync contribution topic. 24 syncContributionWeight = 0.2 25 // attestationTotalWeight specifies the scoring weight that we apply to 26 // our attestation subnet topic. 27 attestationTotalWeight = 1 28 // syncCommitteesTotalWeight specifies the scoring weight that we apply to 29 // our sync subnet topic. 30 syncCommitteesTotalWeight = 0.4 31 // attesterSlashingWeight specifies the scoring weight that we apply to 32 // our attester slashing topic. 33 attesterSlashingWeight = 0.05 34 // proposerSlashingWeight specifies the scoring weight that we apply to 35 // our proposer slashing topic. 36 proposerSlashingWeight = 0.05 37 // voluntaryExitWeight specifies the scoring weight that we apply to 38 // our voluntary exit topic. 39 voluntaryExitWeight = 0.05 40 // blsToExecutionChangeWeight specifies the scoring weight that we apply to 41 // our bls to execution topic. 42 blsToExecutionChangeWeight = 0.05 43 44 // maxInMeshScore describes the max score a peer can attain from being in the mesh. 45 maxInMeshScore = 10 46 // maxFirstDeliveryScore describes the max score a peer can obtain from first deliveries. 47 maxFirstDeliveryScore = 40 48 49 // decayToZero specifies the terminal value that we will use when decaying 50 // a value. 51 decayToZero = 0.01 52 53 // dampeningFactor reduces the amount by which the various thresholds and caps are created. 54 dampeningFactor = 90 55 ) 56 57 var ( 58 // a bool to check if we enable scoring for messages in the mesh sent for near first deliveries. 59 meshDeliveryIsScored = false 60 61 // Defines the variables representing the different time periods. 62 oneHundredBlocks = 100 * oneBlockDuration() 63 invalidDecayPeriod = 50 * oneBlockDuration() 64 twentyBlocks = 20 * oneBlockDuration() 65 tenBlocks = 10 * oneBlockDuration() 66 ) 67 68 func peerScoringParams() (*pubsub.PeerScoreParams, *pubsub.PeerScoreThresholds) { 69 thresholds := &pubsub.PeerScoreThresholds{ 70 GossipThreshold: -4000, 71 PublishThreshold: -8000, 72 GraylistThreshold: -16000, 73 AcceptPXThreshold: 100, 74 OpportunisticGraftThreshold: 5, 75 } 76 scoreParams := &pubsub.PeerScoreParams{ 77 Topics: make(map[string]*pubsub.TopicScoreParams), 78 TopicScoreCap: 32.72, 79 AppSpecificScore: func(p peer.ID) float64 { 80 return 0 81 }, 82 AppSpecificWeight: 1, 83 IPColocationFactorWeight: -35.11, 84 IPColocationFactorThreshold: 10, 85 IPColocationFactorWhitelist: nil, 86 BehaviourPenaltyWeight: -15.92, 87 BehaviourPenaltyThreshold: 6, 88 BehaviourPenaltyDecay: scoreDecay(tenBlocks), 89 DecayInterval: oneBlockDuration(), 90 DecayToZero: decayToZero, 91 RetainScore: oneHundredBlocks, 92 } 93 return scoreParams, thresholds 94 } 95 96 func (s *Service) topicScoreParams(topic string) (*pubsub.TopicScoreParams, error) { 97 switch { 98 case strings.Contains(topic, GossipBlockMessage): 99 return defaultBlockTopicParams(), nil 100 case strings.Contains(topic, GossipExitMessage): 101 return defaultVoluntaryExitTopicParams(), nil 102 default: 103 return nil, errors.Errorf("unrecognized topic provided for parameter registration: %s", topic) 104 } 105 } 106 107 // Based on the lighthouse parameters. 108 // https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c 109 110 func defaultBlockTopicParams() *pubsub.TopicScoreParams { 111 //todo 112 decayEpoch := time.Duration(5) 113 meshWeight := -0.717 114 if !meshDeliveryIsScored { 115 // Set the mesh weight as zero as a temporary measure, so as to prevent 116 // the average nodes from being penalised. 117 meshWeight = 0 118 } 119 return &pubsub.TopicScoreParams{ 120 TopicWeight: beaconBlockWeight, 121 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 122 TimeInMeshQuantum: inMeshTime(), 123 TimeInMeshCap: inMeshCap(), 124 FirstMessageDeliveriesWeight: 1, 125 FirstMessageDeliveriesDecay: scoreDecay(twentyBlocks), 126 FirstMessageDeliveriesCap: 23, 127 MeshMessageDeliveriesWeight: meshWeight, 128 MeshMessageDeliveriesDecay: scoreDecay(decayEpoch * oneBlockDuration()), 129 MeshMessageDeliveriesCap: float64(decayEpoch), 130 MeshMessageDeliveriesThreshold: float64(decayEpoch) / 10, 131 MeshMessageDeliveriesWindow: 2 * time.Second, 132 MeshMessageDeliveriesActivation: 4 * oneBlockDuration(), 133 MeshFailurePenaltyWeight: meshWeight, 134 MeshFailurePenaltyDecay: scoreDecay(decayEpoch * oneBlockDuration()), 135 InvalidMessageDeliveriesWeight: -140.4475, 136 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 137 } 138 } 139 140 func defaultSyncContributionTopicParams() *pubsub.TopicScoreParams { 141 // Determine the expected message rate for the particular gossip topic. 142 //todo 143 aggPerSlot := 2 144 firstMessageCap, err := decayLimit(scoreDecay(1*oneBlockDuration()), float64(aggPerSlot*2/gossipSubD)) 145 if err != nil { 146 log.Warn("skipping initializing topic scoring", "err", err) 147 return nil 148 } 149 firstMessageWeight := maxFirstDeliveryScore / firstMessageCap 150 meshThreshold, err := decayThreshold(scoreDecay(1*oneBlockDuration()), float64(aggPerSlot)/dampeningFactor) 151 if err != nil { 152 log.Warn("skipping initializing topic scoring", "err", err) 153 return nil 154 } 155 meshWeight := -scoreByWeight(syncContributionWeight, meshThreshold) 156 meshCap := 4 * meshThreshold 157 if !meshDeliveryIsScored { 158 // Set the mesh weight as zero as a temporary measure, so as to prevent 159 // the average nodes from being penalised. 160 meshWeight = 0 161 } 162 return &pubsub.TopicScoreParams{ 163 TopicWeight: syncContributionWeight, 164 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 165 TimeInMeshQuantum: inMeshTime(), 166 TimeInMeshCap: inMeshCap(), 167 FirstMessageDeliveriesWeight: firstMessageWeight, 168 FirstMessageDeliveriesDecay: scoreDecay(1 * oneBlockDuration()), 169 FirstMessageDeliveriesCap: firstMessageCap, 170 MeshMessageDeliveriesWeight: meshWeight, 171 MeshMessageDeliveriesDecay: scoreDecay(1 * oneBlockDuration()), 172 MeshMessageDeliveriesCap: meshCap, 173 MeshMessageDeliveriesThreshold: meshThreshold, 174 MeshMessageDeliveriesWindow: 2 * time.Second, 175 MeshMessageDeliveriesActivation: 1 * oneBlockDuration(), 176 MeshFailurePenaltyWeight: meshWeight, 177 MeshFailurePenaltyDecay: scoreDecay(1 * oneBlockDuration()), 178 InvalidMessageDeliveriesWeight: -maxScore() / syncContributionWeight, 179 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 180 } 181 } 182 183 func defaultAttesterSlashingTopicParams() *pubsub.TopicScoreParams { 184 return &pubsub.TopicScoreParams{ 185 TopicWeight: attesterSlashingWeight, 186 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 187 TimeInMeshQuantum: inMeshTime(), 188 TimeInMeshCap: inMeshCap(), 189 FirstMessageDeliveriesWeight: 36, 190 FirstMessageDeliveriesDecay: scoreDecay(oneHundredBlocks), 191 FirstMessageDeliveriesCap: 1, 192 MeshMessageDeliveriesWeight: 0, 193 MeshMessageDeliveriesDecay: 0, 194 MeshMessageDeliveriesCap: 0, 195 MeshMessageDeliveriesThreshold: 0, 196 MeshMessageDeliveriesWindow: 0, 197 MeshMessageDeliveriesActivation: 0, 198 MeshFailurePenaltyWeight: 0, 199 MeshFailurePenaltyDecay: 0, 200 InvalidMessageDeliveriesWeight: -2000, 201 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 202 } 203 } 204 205 func defaultProposerSlashingTopicParams() *pubsub.TopicScoreParams { 206 return &pubsub.TopicScoreParams{ 207 TopicWeight: proposerSlashingWeight, 208 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 209 TimeInMeshQuantum: inMeshTime(), 210 TimeInMeshCap: inMeshCap(), 211 FirstMessageDeliveriesWeight: 36, 212 FirstMessageDeliveriesDecay: scoreDecay(oneHundredBlocks), 213 FirstMessageDeliveriesCap: 1, 214 MeshMessageDeliveriesWeight: 0, 215 MeshMessageDeliveriesDecay: 0, 216 MeshMessageDeliveriesCap: 0, 217 MeshMessageDeliveriesThreshold: 0, 218 MeshMessageDeliveriesWindow: 0, 219 MeshMessageDeliveriesActivation: 0, 220 MeshFailurePenaltyWeight: 0, 221 MeshFailurePenaltyDecay: 0, 222 InvalidMessageDeliveriesWeight: -2000, 223 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 224 } 225 } 226 227 func defaultVoluntaryExitTopicParams() *pubsub.TopicScoreParams { 228 return &pubsub.TopicScoreParams{ 229 TopicWeight: voluntaryExitWeight, 230 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 231 TimeInMeshQuantum: inMeshTime(), 232 TimeInMeshCap: inMeshCap(), 233 FirstMessageDeliveriesWeight: 2, 234 FirstMessageDeliveriesDecay: scoreDecay(oneHundredBlocks), 235 FirstMessageDeliveriesCap: 5, 236 MeshMessageDeliveriesWeight: 0, 237 MeshMessageDeliveriesDecay: 0, 238 MeshMessageDeliveriesCap: 0, 239 MeshMessageDeliveriesThreshold: 0, 240 MeshMessageDeliveriesWindow: 0, 241 MeshMessageDeliveriesActivation: 0, 242 MeshFailurePenaltyWeight: 0, 243 MeshFailurePenaltyDecay: 0, 244 InvalidMessageDeliveriesWeight: -2000, 245 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 246 } 247 } 248 249 func defaultBlsToExecutionChangeTopicParams() *pubsub.TopicScoreParams { 250 return &pubsub.TopicScoreParams{ 251 TopicWeight: blsToExecutionChangeWeight, 252 TimeInMeshWeight: maxInMeshScore / inMeshCap(), 253 TimeInMeshQuantum: inMeshTime(), 254 TimeInMeshCap: inMeshCap(), 255 FirstMessageDeliveriesWeight: 2, 256 FirstMessageDeliveriesDecay: scoreDecay(oneHundredBlocks), 257 FirstMessageDeliveriesCap: 5, 258 MeshMessageDeliveriesWeight: 0, 259 MeshMessageDeliveriesDecay: 0, 260 MeshMessageDeliveriesCap: 0, 261 MeshMessageDeliveriesThreshold: 0, 262 MeshMessageDeliveriesWindow: 0, 263 MeshMessageDeliveriesActivation: 0, 264 MeshFailurePenaltyWeight: 0, 265 MeshFailurePenaltyDecay: 0, 266 InvalidMessageDeliveriesWeight: -2000, 267 InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), 268 } 269 } 270 271 func oneBlockDuration() time.Duration { 272 //todo 273 return 8 * time.Second 274 } 275 276 // determines the decay rate from the provided time period till 277 // the decayToZero value. Ex: ( 1 -> 0.01) 278 func scoreDecay(totalDurationDecay time.Duration) float64 { 279 numOfTimes := totalDurationDecay / oneBlockDuration() 280 return math.Pow(decayToZero, 1/float64(numOfTimes)) 281 } 282 283 // is used to determine the threshold from the decay limit with 284 // a provided growth rate. This applies the decay rate to a 285 // computed limit. 286 func decayThreshold(decayRate, rate float64) (float64, error) { 287 d, err := decayLimit(decayRate, rate) 288 if err != nil { 289 return 0, err 290 } 291 return d * decayRate, nil 292 } 293 294 // decayLimit provides the value till which a decay process will 295 // limit till provided with an expected growth rate. 296 func decayLimit(decayRate, rate float64) (float64, error) { 297 if 1 <= decayRate { 298 return 0, errors.Errorf("got an invalid decayLimit rate: %f", decayRate) 299 } 300 return rate / (1 - decayRate), nil 301 } 302 303 // provides the relevant score by the provided weight and threshold. 304 func scoreByWeight(weight, threshold float64) float64 { 305 return maxScore() / (weight * threshold * threshold) 306 } 307 308 // maxScore attainable by a peer. 309 func maxScore() float64 { 310 totalWeight := beaconBlockWeight + aggregateWeight + syncContributionWeight + 311 attestationTotalWeight + syncCommitteesTotalWeight + attesterSlashingWeight + 312 proposerSlashingWeight + voluntaryExitWeight + blsToExecutionChangeWeight 313 return (maxInMeshScore + maxFirstDeliveryScore) * totalWeight 314 } 315 316 // denotes the unit time in mesh for scoring tallying. 317 func inMeshTime() time.Duration { 318 return 1 * oneBlockDuration() 319 } 320 321 // the cap for `inMesh` time scoring. 322 func inMeshCap() float64 { 323 return float64((3600 * time.Second) / inMeshTime()) 324 } 325 326 func logGossipParameters(topic string, params *pubsub.TopicScoreParams) { 327 // Exit early in the event the parameter struct is nil. 328 if params == nil { 329 return 330 } 331 rawParams := reflect.ValueOf(params).Elem() 332 numOfFields := rawParams.NumField() 333 334 fields := make([]interface{}, numOfFields*2) 335 for i := 0; i < numOfFields; i++ { 336 fields = append(fields, reflect.TypeOf(params).Elem().Field(i).Name, rawParams.Field(i).Interface()) 337 } 338 log.Debug(fmt.Sprintf("Topic Parameters for %s", topic), fields...) 339 }