@@ -150,34 +150,78 @@ func run(ctx context.Context, rpcEndpoint string, jwt string, f3RpcEndpoint stri
150
150
}
151
151
}()
152
152
153
+ var lastMsgToSignTimestamp time.Time
154
+ var lastMsgToSign * gpbft.MessageBuilder
155
+ lastMsgSigningMiners := make (map [uint64 ]struct {})
156
+
157
+ // Send the last gpbft message for each new participant,
158
+ // see <https://github.com/filecoin-project/lotus/pull/12577>
159
+ if isJwtProvided {
160
+ go func () {
161
+ for {
162
+ // Send only when no messages are received in the last 10s.
163
+ // This is to avoid a deadlock situation where everyone is waiting
164
+ // for the next round to participate, but we'll never get there
165
+ // because not enough participants acted in the current round.
166
+ if lastMsgToSign != nil && lastMsgToSignTimestamp .Add (10 * time .Second ).Before (time .Now ()) {
167
+ if miners , err := ec .f3api .GetParticipatingMinerIDs (ctx ); err == nil {
168
+ for _ , miner := range miners {
169
+ if _ , ok := lastMsgSigningMiners [miner ]; ok {
170
+ continue
171
+ } else if err := participate (ctx , f3Module , & ec , lastMsgToSign , miner ); err != nil {
172
+ logger .Warn (err )
173
+ } else {
174
+ lastMsgSigningMiners [miner ] = struct {}{}
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ time .Sleep (1 * time .Second )
181
+ }
182
+ }()
183
+ }
184
+
153
185
for {
154
186
msgToSign := <- f3Module .MessagesToSign ()
187
+ lastMsgToSignTimestamp = time .Now ()
188
+ lastMsgToSign = msgToSign
155
189
miners , err := ec .f3api .GetParticipatingMinerIDs (ctx )
156
190
if err != nil {
157
191
continue
158
192
}
193
+ // Clear the map
194
+ clear (lastMsgSigningMiners )
159
195
if ! isJwtProvided && len (miners ) > 0 {
160
196
logger .Warn ("Unable to sign messages, jwt for Forest RPC endpoint is not provided." )
161
197
}
162
- if isJwtProvided {
198
+ if isJwtProvided && msgToSign != nil {
163
199
for _ , miner := range miners {
164
- signatureBuilder , err := msgToSign .PrepareSigningInputs (gpbft .ActorID (miner ))
165
- if err != nil {
166
- if errors .Is (err , gpbft .ErrNoPower ) {
167
- // we don't have any power in F3, continue
168
- logger .Warnf ("no power to participate in F3: %+v" , err )
169
- } else {
170
- logger .Warnf ("preparing signing inputs: %+v" , err )
171
- }
172
- continue
200
+ if err := participate (ctx , f3Module , & ec , msgToSign , miner ); err != nil {
201
+ logger .Warn (err )
202
+ } else {
203
+ lastMsgSigningMiners [miner ] = struct {}{}
173
204
}
174
- payloadSig , vrfSig , err := signatureBuilder .Sign (ctx , & ec )
175
- if err != nil {
176
- logger .Warnf ("signing message: %+v" , err )
177
- }
178
- logger .Debugf ("miner with id %d is sending message in F3" , miner )
179
- f3Module .Broadcast (ctx , signatureBuilder , payloadSig , vrfSig )
180
205
}
181
206
}
182
207
}
183
208
}
209
+
210
+ func participate (ctx context.Context , f3Module * f3.F3 , signer gpbft.Signer , msgToSign * gpbft.MessageBuilder , miner uint64 ) error {
211
+ signatureBuilder , err := msgToSign .PrepareSigningInputs (gpbft .ActorID (miner ))
212
+ if err != nil {
213
+ if errors .Is (err , gpbft .ErrNoPower ) {
214
+ // we don't have any power in F3, continue
215
+ return fmt .Errorf ("no power to participate in F3: %+v" , err )
216
+ } else {
217
+ return fmt .Errorf ("preparing signing inputs: %+v" , err )
218
+ }
219
+ }
220
+ payloadSig , vrfSig , err := signatureBuilder .Sign (ctx , signer )
221
+ if err != nil {
222
+ logger .Warnf ("signing message: %+v" , err )
223
+ }
224
+ logger .Debugf ("miner with id %d is sending message in F3" , miner )
225
+ f3Module .Broadcast (ctx , signatureBuilder , payloadSig , vrfSig )
226
+ return nil
227
+ }
0 commit comments