@@ -117,6 +117,90 @@ func (params *Params) WithPrivateKey(privatekey *ecdsa.PrivateKey) *Params {
117
117
return params
118
118
}
119
119
120
+ type outbox struct {
121
+ queue []* outboxMsg
122
+ slots chan int
123
+ process chan int
124
+ quitC chan struct {}
125
+ forward func (msg * PssMsg ) error
126
+ }
127
+
128
+ func newOutbox (capacity int , quitC chan struct {}, forward func (msg * PssMsg ) error ) outbox {
129
+ outbox := outbox {
130
+ queue : make ([]* outboxMsg , capacity ),
131
+ slots : make (chan int , capacity ),
132
+ process : make (chan int ),
133
+ quitC : quitC ,
134
+ forward : forward ,
135
+ }
136
+ // fill up outbox slots
137
+ for i := 0 ; i < cap (outbox .slots ); i ++ {
138
+ outbox .slots <- i
139
+ }
140
+ return outbox
141
+ }
142
+
143
+ func (o outbox ) len () int {
144
+ return cap (o .slots ) - len (o .slots )
145
+ }
146
+
147
+ // enqueue a new element in the outbox if there is any slot available.
148
+ // Then send it to process. This method is blocking in the process channel!
149
+ func (o * outbox ) enqueue (outboxmsg * outboxMsg ) error {
150
+ // first we try to obtain a slot in the outbox
151
+ select {
152
+ case slot := <- o .slots :
153
+ o .queue [slot ] = outboxmsg
154
+ metrics .GetOrRegisterGauge ("pss.outbox.len" , nil ).Update (int64 (o .len ()))
155
+ // we send this message slot to process
156
+ select {
157
+ case o .process <- slot :
158
+ case <- o .quitC :
159
+ }
160
+ return nil
161
+ default :
162
+ metrics .GetOrRegisterCounter ("pss.enqueue.outbox.full" , nil ).Inc (1 )
163
+ return errors .New ("outbox full" )
164
+ }
165
+ }
166
+
167
+ func (o * outbox ) processOutbox () {
168
+ for slot := range o .process {
169
+ go func (slot int ) {
170
+ msg := o .msg (slot )
171
+ metrics .GetOrRegisterResettingTimer ("pss.handle.outbox" , nil ).UpdateSince (msg .startedAt )
172
+ if err := o .forward (msg .msg ); err != nil {
173
+ metrics .GetOrRegisterCounter ("pss.forward.err" , nil ).Inc (1 )
174
+ // if we failed to forward, re-insert message in the queue
175
+ log .Debug (err .Error ())
176
+ // reenqueue the message for processing
177
+ o .reenqueue (slot )
178
+ log .Debug ("Message re-enqued" , "slot" , slot )
179
+ return
180
+ }
181
+ // free the outbox slot
182
+ o .free (slot )
183
+ metrics .GetOrRegisterGauge ("pss.outbox.len" , nil ).Update (int64 (o .len ()))
184
+ }(slot )
185
+ }
186
+ }
187
+
188
+ func (o outbox ) msg (slot int ) * outboxMsg {
189
+ return o .queue [slot ]
190
+ }
191
+
192
+ func (o outbox ) free (slot int ) {
193
+ o .slots <- slot
194
+ }
195
+
196
+ func (o outbox ) reenqueue (slot int ) {
197
+ select {
198
+ case o .process <- slot :
199
+ case <- o .quitC :
200
+ }
201
+
202
+ }
203
+
120
204
// Pss is the top-level struct, which takes care of message sending, receiving, decryption and encryption, message handler dispatchers
121
205
// and message forwarding. Implements node.Service
122
206
type Pss struct {
@@ -136,7 +220,7 @@ type Pss struct {
136
220
msgTTL time.Duration
137
221
paddingByteSize int
138
222
capstring string
139
- outbox chan * outboxMsg
223
+ outbox outbox
140
224
141
225
// message handling
142
226
handlers map [Topic ]map [* handler ]bool // topic and version based pss payload handlers. See pss.Handle()
@@ -178,7 +262,6 @@ func New(k *network.Kademlia, params *Params) (*Pss, error) {
178
262
msgTTL : params .MsgTTL ,
179
263
paddingByteSize : defaultPaddingByteSize ,
180
264
capstring : c .String (),
181
- outbox : make (chan * outboxMsg , defaultOutboxCapacity ),
182
265
183
266
handlers : make (map [Topic ]map [* handler ]bool ),
184
267
topicHandlerCaps : make (map [Topic ]* handlerCaps ),
@@ -189,6 +272,7 @@ func New(k *network.Kademlia, params *Params) (*Pss, error) {
189
272
},
190
273
},
191
274
}
275
+ ps .outbox = newOutbox (defaultOutboxCapacity , ps .quitC , ps .forward )
192
276
193
277
for i := 0 ; i < hasherCount ; i ++ {
194
278
hashfunc := storage .MakeHashFunc (storage .DefaultHash )()
@@ -219,23 +303,10 @@ func (p *Pss) Start(srv *p2p.Server) error {
219
303
}
220
304
}
221
305
}()
222
- go func () {
223
- for {
224
- select {
225
- case msg := <- p .outbox :
226
- metrics .GetOrRegisterGauge ("pss.outbox.len" , nil ).Update (int64 (len (p .outbox )))
227
-
228
- err := p .forward (msg .msg )
229
- if err != nil {
230
- log .Error (err .Error ())
231
- metrics .GetOrRegisterCounter ("pss.forward.err" , nil ).Inc (1 )
232
- }
233
- metrics .GetOrRegisterResettingTimer ("pss.handle.outbox" , nil ).UpdateSince (msg .startedAt )
234
- case <- p .quitC :
235
- return
236
- }
237
- }
238
- }()
306
+
307
+ // Forward outbox messages
308
+ go p .outbox .processOutbox ()
309
+
239
310
log .Info ("Started Pss" )
240
311
log .Info ("Loaded EC keys" , "pubkey" , common .ToHex (crypto .FromECDSAPub (p .PublicKey ())), "secp256" , common .ToHex (crypto .CompressPubkey (p .PublicKey ())))
241
312
return nil
@@ -557,16 +628,8 @@ func (p *Pss) enqueue(msg *PssMsg) error {
557
628
defer metrics .GetOrRegisterResettingTimer ("pss.enqueue" , nil ).UpdateSince (time .Now ())
558
629
559
630
outboxmsg := newOutboxMsg (msg )
560
- select {
561
- case p .outbox <- outboxmsg :
562
- metrics .GetOrRegisterGauge ("pss.outbox.len" , nil ).Update (int64 (len (p .outbox )))
563
631
564
- return nil
565
- default :
566
- }
567
-
568
- metrics .GetOrRegisterCounter ("pss.enqueue.outbox.full" , nil ).Inc (1 )
569
- return errors .New ("outbox full" )
632
+ return p .outbox .enqueue (outboxmsg )
570
633
}
571
634
572
635
// Send a raw message (any encryption is responsibility of calling client)
@@ -730,8 +793,8 @@ func sendMsg(p *Pss, sp *network.Peer, msg *PssMsg) bool {
730
793
// node, then it will be forwarded to all the nearest neighbours of the forwarding node. In case of
731
794
// partial address, it should be forwarded to all the peers matching the partial address, if there
732
795
// are any; otherwise only to one peer, closest to the recipient address. In any case, if the message
733
- // forwarding fails, the node should try to forward it to the next best peer, until the message is
734
- // successfully forwarded to at least one peer.
796
+ //// forwarding fails, the node should try to forward it to the next best peer, until the message is
797
+ //// successfully forwarded to at least one peer.
735
798
func (p * Pss ) forward (msg * PssMsg ) error {
736
799
metrics .GetOrRegisterCounter ("pss.forward" , nil ).Inc (1 )
737
800
sent := 0 // number of successful sends
@@ -779,19 +842,14 @@ func (p *Pss) forward(msg *PssMsg) error {
779
842
return true
780
843
})
781
844
782
- // if we failed to send to anyone, re-insert message in the send-queue
783
- if sent == 0 {
784
- log .Debug ("unable to forward to any peers" )
785
- if err := p .enqueue (msg ); err != nil {
786
- metrics .GetOrRegisterCounter ("pss.forward.enqueue.error" , nil ).Inc (1 )
787
- log .Error (err .Error ())
788
- return err
789
- }
790
- }
791
-
792
845
// cache the message
793
846
p .addFwdCache (msg )
794
- return nil
847
+
848
+ if sent == 0 {
849
+ return errors .New ("unable to forward to any peers" )
850
+ } else {
851
+ return nil
852
+ }
795
853
}
796
854
797
855
/////////////////////////////////////////////////////////////////////
0 commit comments