github.com/annchain/OG@v0.0.9/consensus/dkg/dkg_partner.go (about) 1 package dkg 2 3 import ( 4 "github.com/annchain/OG/arefactor/common/goroutine" 5 "github.com/annchain/OG/common/hexutil" 6 "github.com/annchain/OG/ffchan" 7 "github.com/annchain/kyber/v3" 8 "github.com/annchain/kyber/v3/pairing/bn256" 9 dkger "github.com/annchain/kyber/v3/share/dkg/pedersen" 10 vss "github.com/annchain/kyber/v3/share/vss/pedersen" 11 "github.com/sirupsen/logrus" 12 "sync" 13 "time" 14 ) 15 16 // DefaultDkgPartner is the parter in a DKG group built to discuss a pub/privkey 17 // It will receive DKG messages and update the status. 18 // It is the handler for maintaining the DkgContext. 19 // Campaign or term change is not part of DKGPartner. Do their job in their own module. 20 type DefaultDkgPartner struct { 21 context *DkgContext 22 peerCommunicatorIncoming DkgPeerCommunicatorIncoming 23 peerCommunicatorOutgoing DkgPeerCommunicatorOutgoing 24 dealReceivingCache DisorderedCache // map[deal_sender_index]Deal 25 gossipStartCh chan bool 26 27 otherPeers []DkgPeer 28 notified bool 29 DealResponseCache map[int]*dkger.Response //my response for such deal should not be generated twice 30 ResponseCache map[string]bool // duplicate response should not be processed twice. 31 total int 32 dkgGeneratedListeners []DkgGeneratedListener // joint pubkey is got 33 34 quit chan bool 35 quitWg sync.WaitGroup 36 } 37 38 func (p *DefaultDkgPartner) GetDkgPeerCommunicatorIncoming() DkgPeerCommunicatorIncoming { 39 return p.peerCommunicatorIncoming 40 } 41 42 func (p *DefaultDkgPartner) Stop() { 43 close(p.quit) 44 p.quitWg.Wait() 45 } 46 47 // NewDefaultDkgPartner inits a dkg group. All public keys should be already generated 48 // The public keys are shared before the Dkg group can be formed. 49 // This may be done by publishing partPub to the blockchain 50 // termId is still needed to identify different Dkg groups 51 // allPeers needs to be sorted and globally order identical 52 func NewDefaultDkgPartner(suite *bn256.Suite, termId uint32, numParts, threshold int, allPeers []PartPub, me PartSec, 53 dkgPeerCommunicatorIncoming DkgPeerCommunicatorIncoming, 54 dkgPeerCommunicatorOutgoing DkgPeerCommunicatorOutgoing) (*DefaultDkgPartner, error) { 55 // new dkg context 56 c := NewDkgContext(suite, termId) 57 c.NbParticipants = numParts 58 c.Threshold = threshold 59 c.PartPubs = allPeers 60 c.Me = me 61 62 // find Who am I 63 myIndex := -1 64 for i := 0; i < len(allPeers); i++ { 65 if allPeers[i].Point.Equal(me.Point) { 66 // That's me 67 myIndex = i 68 break 69 } 70 } 71 if myIndex == -1 { 72 panic("did not find myself") 73 } 74 c.MyIndex = uint32(myIndex) 75 76 // setup partner 77 d := &DefaultDkgPartner{ 78 context: c, 79 peerCommunicatorIncoming: dkgPeerCommunicatorIncoming, 80 peerCommunicatorOutgoing: dkgPeerCommunicatorOutgoing, 81 dealReceivingCache: make(DisorderedCache), 82 gossipStartCh: make(chan bool), 83 otherPeers: []DkgPeer{}, 84 notified: false, 85 DealResponseCache: make(map[int]*dkger.Response), 86 ResponseCache: make(map[string]bool), 87 total: 0, 88 dkgGeneratedListeners: []DkgGeneratedListener{}, 89 quit: make(chan bool), 90 quitWg: sync.WaitGroup{}, 91 } 92 93 // init all other peers so that I can do broadcast 94 for i := 0; i < len(allPeers); i++ { 95 if i == int(c.MyIndex) { 96 continue 97 } 98 d.otherPeers = append(d.otherPeers, allPeers[i].Peer) 99 } 100 101 if err := c.GenerateDKGer(); err != nil { 102 // cannot build dkg group using these pubkeys 103 return nil, err 104 } 105 return d, nil 106 107 } 108 109 // GenPartnerPair generates a part private/public key for discussing with others. 110 func GenPartnerPair(suite *bn256.Suite) (kyber.Scalar, kyber.Point) { 111 sc := suite.Scalar().Pick(suite.RandomStream()) 112 return sc, suite.Point().Mul(sc, nil) 113 } 114 115 func (p *DefaultDkgPartner) Start() { 116 // start to gossipLoop and share the deals 117 p.quitWg.Add(1) 118 goroutine.New(p.gossipLoop) 119 } 120 121 func (p *DefaultDkgPartner) gossipLoop() { 122 select { 123 case <-p.gossipStartCh: 124 logrus.Debug("dkg gossip started") 125 break 126 case <-p.quit: 127 logrus.Debug("dkg gossip quit") 128 return 129 } 130 pipeOutChannel := p.peerCommunicatorIncoming.GetPipeOut() 131 // send the deals to all other partners 132 go p.announceDeals() 133 for { 134 timer := time.NewTimer(time.Second * 10) 135 select { 136 case <-p.quit: 137 logrus.Warn("dkg gossip quit") 138 p.quitWg.Done() 139 return 140 case <-timer.C: 141 logrus.WithField("IM", p.context.Me.Peer.Address.ShortString()).Warn("Blocked reading incoming dkg") 142 //p.checkWaitingForWhat() 143 case msgEvent := <-pipeOutChannel: 144 logrus.WithField("me", p.context.MyIndex).WithField("type", msgEvent.Message.GetType()).Trace("received a message") 145 p.handleMessage(msgEvent) 146 } 147 } 148 149 } 150 151 // announceDeals sends deals to all other partners to build up a dkg group 152 func (p *DefaultDkgPartner) announceDeals() { 153 // get all deals that needs to be sent to other partners 154 deals, err := p.context.Dkger.Deals() 155 if err != nil { 156 logrus.WithError(err).Fatal("failed to generate dkg deals") 157 } 158 for i, deal := range deals { 159 p.sendDealToPartner(i, deal) 160 } 161 162 // in case of package loss, keep resending 163 //for { 164 // time.Sleep(time.Second * 60) 165 // logrus.Warn("RESEND") 166 // for i, deal := range deals { 167 // p.sendDealToPartner(i, deal) 168 // } 169 //} 170 } 171 172 // sendDealToPartner unicast a deal message to some specific partner 173 func (p *DefaultDkgPartner) sendDealToPartner(id int, deal *dkger.Deal) { 174 data, err := deal.MarshalMsg(nil) 175 if err != nil { 176 logrus.WithError(err).Fatal("cannot marshal dkg deal") 177 } 178 179 msg := &MessageDkgDeal{ 180 DkgBasicInfo: DkgBasicInfo{ 181 TermId: p.context.SessionId, 182 }, 183 Data: data, 184 } 185 logrus.WithField("from", deal.Index).WithField("to", id). 186 Trace("unicasting deal message") 187 p.peerCommunicatorOutgoing.Unicast(msg, p.context.PartPubs[id].Peer) 188 // after this, you are expecting a response from the target peers 189 } 190 191 func (p *DefaultDkgPartner) sendResponseToAllRestPartners(response *dkger.Response) { 192 data, err := response.MarshalMsg(nil) 193 if err != nil { 194 // TODO: change it to warn maybe 195 logrus.WithError(err).Fatal("cannot marshal dkg response") 196 return 197 } 198 199 msg := &MessageDkgDealResponse{ 200 DkgBasicInfo: DkgBasicInfo{ 201 TermId: p.context.SessionId, 202 }, 203 Data: data, 204 } 205 logrus.WithField("me", p.context.MyIndex).WithField("from", response.Response.Index).Trace("broadcasting response message") 206 p.peerCommunicatorOutgoing.Broadcast(msg, p.otherPeers) 207 } 208 209 func (p *DefaultDkgPartner) handleMessage(msgEvent *DkgMessageEvent) { 210 message := msgEvent.Message 211 switch message.GetType() { 212 case DkgMessageTypeDeal: 213 msg, ok := message.(*MessageDkgDeal) 214 if !ok { 215 logrus.Warn("it claims to be a MessageDkgDeal but the payload does not align") 216 return 217 } 218 p.handleDealMessage(msg) 219 case DkgMessageTypeDealResponse: 220 msg, ok := message.(*MessageDkgDealResponse) 221 if !ok { 222 logrus.Warn("it claims to be a MessageDkgDealResponse but the payload does not align") 223 return 224 } 225 p.handleDealResponseMessage(msg) 226 default: 227 logrus.WithField("type", message.GetType()).Warn("unknown dkg message type") 228 } 229 } 230 231 func (p *DefaultDkgPartner) handleDealMessage(msg *MessageDkgDeal) { 232 deal, err := msg.GetDeal() 233 if err != nil { 234 logrus.Warn("failed to unmarshal dkg deal message") 235 return 236 } 237 // verify if deal's sender has a unified index and pubkey to avoid fake messages. 238 err = p.verifyDealSender(msg, deal) 239 if err != nil { 240 logrus.WithError(err).Warn("wrong sender for dkg deal") 241 return 242 } 243 244 issuerIndex := deal.Index 245 v, hasPreviousDiscussion := p.dealReceivingCache[issuerIndex] 246 if !hasPreviousDiscussion { 247 v = &DkgDiscussion{ 248 Deal: nil, 249 Responses: []*dkger.Response{}, 250 } 251 logrus.WithField("me", p.context.MyIndex).WithField("from", deal.Index).Trace("no previous discussion found in cache. new deal.") 252 } else { 253 logrus.WithField("me", p.context.MyIndex).WithField("from", deal.Index).Trace("previous discussion found in cache.") 254 } 255 256 //resp, inDealResponseCache := p.DealResponseCache[hexutil.Encode(deal.Signature)] 257 resp, inDealResponseCache := p.DealResponseCache[int(deal.Index)] 258 // if the resp is already generated, do not generate for the second time since it will error out. 259 if !inDealResponseCache { 260 // generate response and send out 261 //p.dumpDeal(deal) 262 //p.writeMessage(fmt.Sprintf("Process Deal %d", deal.Index)) 263 resp, err := p.context.Dkger.ProcessDeal(deal) 264 if err != nil { 265 logrus.WithError(err).Warn("failed to process deal") 266 return 267 } 268 if resp.Response.Status != vss.StatusApproval { 269 logrus.Warn("received a deal for rejection") 270 } 271 // cache the deal 272 discussion := v.(*DkgDiscussion) 273 discussion.Deal = deal 274 275 // update state 276 p.dealReceivingCache[issuerIndex] = discussion 277 278 // send response to all other partners except itself 279 //p.writeMessage(fmt.Sprintf("Send Resp %d %d", resp.Index, resp.Response.Index)) 280 p.sendResponseToAllRestPartners(resp) 281 // avoid response regeneration 282 //p.DealResponseCache[hexutil.Encode(deal.Signature)] = resp 283 p.DealResponseCache[int(deal.Index)] = resp 284 285 // TODOļ¼ BUGGY 286 if hasPreviousDiscussion && discussion.GetCurrentStage() >= StageDealReceived { 287 // now deal is just coming. Process the previous deal Responses 288 for _, response := range discussion.Responses { 289 //p.writeMessage(fmt.Sprintf("Process cached Resp %d %d", response.Index, response.Response.Index)) 290 p.handleResponse(response) 291 } 292 // clear the discussion response list since we won't process it twice 293 discussion.Responses = []*dkger.Response{} 294 } else { 295 //p.writeMessage(fmt.Sprintf("not a cached way: %d", discussion.Deal.Index)) 296 } 297 } else { 298 // RE-send response to all other partners except itself 299 //p.writeMessage(fmt.Sprintf("Send Resp %d %d", resp.Index, resp.Response.Index)) 300 p.sendResponseToAllRestPartners(resp) 301 } 302 } 303 304 func (p *DefaultDkgPartner) handleDealResponseMessage(msg *MessageDkgDealResponse) { 305 resp, err := msg.GetResponse() 306 if err != nil { 307 logrus.Warn("failed to unmarshal dkg response message") 308 return 309 } 310 //p.dumpDealResponseMessage(resp, "received") 311 // verify if response's sender has a unified index and pubkey to avoid fake messages. 312 err = p.verifyResponseSender(msg, resp) 313 if err != nil { 314 logrus.WithError(err).Warn("wrong sender for dkg response") 315 return 316 } 317 // avoid duplication 318 signatureKey := hexutil.Encode(resp.Response.Signature) 319 _, responseDuplicated := p.ResponseCache[signatureKey] 320 if responseDuplicated { 321 logrus.WithField("me", p.context.MyIndex). 322 WithField("from", resp.Response.Index). 323 WithField("deal", resp.Index).Trace("duplicate response, drop") 324 return 325 } else { 326 p.ResponseCache[signatureKey] = true 327 } 328 329 // check if the correspondant deal is in the cache 330 // if not, hang on 331 dealerIndex := resp.Index 332 v, ok := p.dealReceivingCache[dealerIndex] 333 if !ok { 334 // deal from this sender has not been received. put the response to the cache 335 v = &DkgDiscussion{ 336 Deal: nil, 337 Responses: []*dkger.Response{}, 338 } 339 } 340 // currently whatever deal is there, append the response to the cache. 341 // in the future this may be removed once deal is received. 342 discussion := v.(*DkgDiscussion) 343 discussion.Responses = append(discussion.Responses, resp) 344 // update state 345 p.dealReceivingCache[dealerIndex] = discussion 346 //verifierIndex := resp.Response.Index 347 348 // if deal is already there, process this response 349 if discussion.Deal != nil || dealerIndex == p.context.MyIndex { 350 logrus.WithField("me", p.context.MyIndex). 351 WithField("from", resp.Response.Index). 352 WithField("deal", resp.Index).Trace("new resp is being processed") 353 //p.writeMessage(fmt.Sprintf("Process Resp %d %d", resp.Index, resp.Response.Index)) 354 p.handleResponse(resp) 355 } else { 356 logrus.WithField("me", p.context.MyIndex). 357 WithField("from", resp.Response.Index). 358 WithField("deal", resp.Index).Trace("new resp is being cached") 359 //p.writeMessage(fmt.Sprintf("Cached Resp %d %d", resp.Index, resp.Response.Index)) 360 } 361 } 362 363 func (p *DefaultDkgPartner) handleResponse(resp *dkger.Response) { 364 //p.dumpDealResponseMessage(resp, "realin") 365 justification, err := p.context.Dkger.ProcessResponse(resp) 366 if err != nil { 367 logrus.WithError(err).WithField("me", p.context.MyIndex). 368 WithField("from", resp.Response.Index). 369 WithField("deal", resp.Index).Warn("error on processing response") 370 return 371 } 372 if justification != nil { 373 logrus.Warn("justification not nil") 374 // TODO: broadcast the justificaiton to the others to inform that this is a bad node 375 } 376 logrus.WithField("me", p.context.MyIndex). 377 WithField("from", resp.Response.Index). 378 WithField("deal", resp.Index).Trace("response is ok") 379 if !p.notified && p.context.Dkger.ThresholdCertified() { 380 _, err := p.context.RecoverPub() 381 if err != nil { 382 logrus.WithField("me", p.context.MyIndex).Warn("DKG has been generated but pubkey recovery failed") 383 } else { 384 logrus.WithField("me", p.context.MyIndex).WithField("pk", p.context.JointPubKey.String()).Info("DKG has been generated") 385 p.notifyListeners() 386 //p.checkWaitingForWhat() 387 } 388 } 389 } 390 391 func (p *DefaultDkgPartner) verifyDealSender(deal *MessageDkgDeal, deal2 *dkger.Deal) error { 392 return nil 393 } 394 395 func (p *DefaultDkgPartner) verifyResponseSender(response *MessageDkgDealResponse, deal *dkger.Response) error { 396 return nil 397 } 398 399 // notifyListeners notifies listeners who has been registered for dkg generated events 400 func (p *DefaultDkgPartner) notifyListeners() { 401 for _, listener := range p.dkgGeneratedListeners { 402 <-ffchan.NewTimeoutSenderShort(listener.GetDkgGeneratedEventChannel(), true, "listener").C 403 //listener.GetDkgGeneratedEventChannel() <- true 404 } 405 p.notified = true 406 } 407 408 func (p *DefaultDkgPartner) RegisterDkgGeneratedListener(l DkgGeneratedListener) { 409 p.dkgGeneratedListeners = append(p.dkgGeneratedListeners, l) 410 } 411 412 //func (p *DefaultDkgPartner) GetPeerCommunicatorOutgoing() DkgPeerCommunicatorOutgoing { 413 // return p.peerCommunicatorOutgoing 414 //} 415 // 416 //func (p *DefaultDkgPartner) GetPeerCommunicatorIncoming() DkgPeerCommunicatorIncoming { 417 // return p.peerCommunicatorIncoming 418 //} 419 420 // 421 //func (p *DefaultDkgPartner) checkWaitingForWhat() { 422 // 423 // //if p.context.MyIndex != 0 {notified 424 // // return 425 // //} 426 // total := TestNodes 427 // if !p.notified { 428 // logrus.WithField("IM", p.context.MyIndex). 429 // WithField("qual", p.context.Dkger.QUAL()). 430 // Warn("not notified") 431 // } else { 432 // return 433 // } 434 // logrus.WithField("me", p.context.MyIndex). 435 // WithField("qual", len(p.context.Dkger.QUAL())). 436 // WithField("notified", p.notified). 437 // Info("check waiting for what") 438 // 439 // var dealers []int 440 // 441 // for dealer, v := range p.dealReceivingCache { 442 // dealers = append(dealers, int(dealer)) 443 // discussion := v.(*DkgDiscussion) 444 // if dealer != p.context.MyIndex && len(discussion.Responses) != total-2 { 445 // logrus.WithFields(logrus.Fields{ 446 // "IM": p.context.MyIndex, 447 // "len": len(discussion.Responses), 448 // }).Warn("missing") 449 // for _, response := range discussion.Responses { 450 // logrus.WithField("IM", p.context.MyIndex).WithField("deal index", response.Index). 451 // WithField("resp index", response.Response.Index).Warn("resp index") 452 // } 453 // } else if dealer == p.context.MyIndex && len(discussion.Responses) != total-1 { 454 // logrus.WithFields(logrus.Fields{ 455 // "IM": p.context.MyIndex, 456 // "len": len(discussion.Responses), 457 // }).Warn("missing") 458 // for _, response := range discussion.Responses { 459 // logrus.WithField("IM", p.context.MyIndex).WithField("deal index", response.Index). 460 // WithField("resp index", response.Response.Index).Warn("resp index") 461 // } 462 // } 463 // } 464 // sort.Ints(dealers) 465 // logrus.WithField("dealers", dealers).WithField("ok", len(dealers) == total).WithField("IM", p.context.MyIndex).Info("all deals") 466 //} 467 // 468 //func (p *DefaultDkgPartner) dumpDeal(deal *dkger.Deal) { 469 // return 470 // debugPath := "D:/tmp/debug" 471 // file, err := os.OpenFile( 472 // path.Join(debugPath, fmt.Sprintf("deal_%02d.txt", p.context.MyIndex)), 473 // os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 474 // if err != nil { 475 // panic(err) 476 // } 477 // defer file.Close() 478 // _, err = fmt.Fprintf(file, "%d\r\n", deal.Index) 479 // if err != nil { 480 // panic(err) 481 // } 482 //} 483 // 484 //func (p *DefaultDkgPartner) dumpDealResponseMessage(response *dkger.Response, msg string) { 485 // p.total += 1 486 // if p.context.MyIndex == 0 && p.total % 20 == 0{ 487 // fmt.Println(p.total) 488 // } 489 // return 490 // debugPath := "D:/tmp/debug" 491 // file, err := os.OpenFile( 492 // path.Join(debugPath, fmt.Sprintf("resp_%02d_%s.txt", p.context.MyIndex, msg)), 493 // os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 494 // if err != nil { 495 // panic(err) 496 // } 497 // defer file.Close() 498 // _, err = fmt.Fprintf(file, "%d %d\r\n", response.Index, response.Response.Index) 499 // if err != nil { 500 // panic(err) 501 // } 502 //} 503 // 504 //func (p *DefaultDkgPartner) writeMessage(msg string) { 505 // return 506 // debugPath := "D:/tmp/debug" 507 // file, err := os.OpenFile( 508 // path.Join(debugPath, fmt.Sprintf("log_%d.txt", p.context.MyIndex)), 509 // os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 510 // if err != nil { 511 // panic(err) 512 // } 513 // defer file.Close() 514 // _, err = fmt.Fprintf(file, "%s\r\n", msg) 515 // if err != nil { 516 // panic(err) 517 // } 518 //}