github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/qln/msghandler.go (about) 1 package qln 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/mit-dci/lit/logging" 8 9 "github.com/mit-dci/lit/btcutil/txscript" 10 "github.com/mit-dci/lit/lnutil" 11 "github.com/mit-dci/lit/portxo" 12 "github.com/mit-dci/lit/wire" 13 ) 14 15 func (nd *LitNode) registerHandlers() { 16 17 mp := nd.PeerMan.GetMessageProcessor() 18 hf := makeNeoOmniHandler(nd) 19 20 // I used the following command to generate these calls below: 21 // grep -E '^.MSGID_[A-Z_]+ += ' lnutil/msglib.go | awk '{ print $1 }' | while read m; do echo "mp.DefineMessage(lnutil.$m, makeNeoOmniParser(lnutil.$m), hf)" ; done 22 23 mp.DefineMessage(lnutil.MSGID_TEXTCHAT, makeNeoOmniParser(lnutil.MSGID_TEXTCHAT), hf) 24 mp.DefineMessage(lnutil.MSGID_POINTREQ, makeNeoOmniParser(lnutil.MSGID_POINTREQ), hf) 25 mp.DefineMessage(lnutil.MSGID_POINTRESP, makeNeoOmniParser(lnutil.MSGID_POINTRESP), hf) 26 mp.DefineMessage(lnutil.MSGID_CHANDESC, makeNeoOmniParser(lnutil.MSGID_CHANDESC), hf) 27 mp.DefineMessage(lnutil.MSGID_CHANACK, makeNeoOmniParser(lnutil.MSGID_CHANACK), hf) 28 mp.DefineMessage(lnutil.MSGID_SIGPROOF, makeNeoOmniParser(lnutil.MSGID_SIGPROOF), hf) 29 mp.DefineMessage(lnutil.MSGID_CLOSEREQ, makeNeoOmniParser(lnutil.MSGID_CLOSEREQ), hf) 30 mp.DefineMessage(lnutil.MSGID_CLOSERESP, makeNeoOmniParser(lnutil.MSGID_CLOSERESP), hf) 31 mp.DefineMessage(lnutil.MSGID_DELTASIG, makeNeoOmniParser(lnutil.MSGID_DELTASIG), hf) 32 mp.DefineMessage(lnutil.MSGID_SIGREV, makeNeoOmniParser(lnutil.MSGID_SIGREV), hf) 33 mp.DefineMessage(lnutil.MSGID_GAPSIGREV, makeNeoOmniParser(lnutil.MSGID_GAPSIGREV), hf) 34 mp.DefineMessage(lnutil.MSGID_REV, makeNeoOmniParser(lnutil.MSGID_REV), hf) 35 mp.DefineMessage(lnutil.MSGID_HASHSIG, makeNeoOmniParser(lnutil.MSGID_HASHSIG), hf) 36 mp.DefineMessage(lnutil.MSGID_PREIMAGESIG, makeNeoOmniParser(lnutil.MSGID_PREIMAGESIG), hf) 37 mp.DefineMessage(lnutil.MSGID_FWDMSG, makeNeoOmniParser(lnutil.MSGID_FWDMSG), hf) 38 mp.DefineMessage(lnutil.MSGID_FWDAUTHREQ, makeNeoOmniParser(lnutil.MSGID_FWDAUTHREQ), hf) 39 mp.DefineMessage(lnutil.MSGID_SELFPUSH, makeNeoOmniParser(lnutil.MSGID_SELFPUSH), hf) 40 mp.DefineMessage(lnutil.MSGID_WATCH_DESC, makeNeoOmniParser(lnutil.MSGID_WATCH_DESC), hf) 41 mp.DefineMessage(lnutil.MSGID_WATCH_STATEMSG, makeNeoOmniParser(lnutil.MSGID_WATCH_STATEMSG), hf) 42 mp.DefineMessage(lnutil.MSGID_WATCH_DELETE, makeNeoOmniParser(lnutil.MSGID_WATCH_DELETE), hf) 43 mp.DefineMessage(lnutil.MSGID_LINK_DESC, makeNeoOmniParser(lnutil.MSGID_LINK_DESC), hf) 44 mp.DefineMessage(lnutil.MSGID_DLC_OFFER, makeNeoOmniParser(lnutil.MSGID_DLC_OFFER), hf) 45 mp.DefineMessage(lnutil.MSGID_DLC_ACCEPTOFFER, makeNeoOmniParser(lnutil.MSGID_DLC_ACCEPTOFFER), hf) 46 mp.DefineMessage(lnutil.MSGID_DLC_DECLINEOFFER, makeNeoOmniParser(lnutil.MSGID_DLC_DECLINEOFFER), hf) 47 mp.DefineMessage(lnutil.MSGID_DLC_CONTRACTACK, makeNeoOmniParser(lnutil.MSGID_DLC_CONTRACTACK), hf) 48 mp.DefineMessage(lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS, makeNeoOmniParser(lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS), hf) 49 mp.DefineMessage(lnutil.MSGID_DLC_SIGPROOF, makeNeoOmniParser(lnutil.MSGID_DLC_SIGPROOF), hf) 50 mp.DefineMessage(lnutil.MSGID_DUALFUNDINGREQ, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGREQ), hf) 51 mp.DefineMessage(lnutil.MSGID_DUALFUNDINGACCEPT, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGACCEPT), hf) 52 mp.DefineMessage(lnutil.MSGID_DUALFUNDINGDECL, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGDECL), hf) 53 mp.DefineMessage(lnutil.MSGID_DUALFUNDINGCHANACK, makeNeoOmniParser(lnutil.MSGID_DUALFUNDINGCHANACK), hf) 54 mp.DefineMessage(lnutil.MSGID_REMOTE_RPCREQUEST, makeNeoOmniParser(lnutil.MSGID_REMOTE_RPCREQUEST), hf) 55 mp.DefineMessage(lnutil.MSGID_REMOTE_RPCRESPONSE, makeNeoOmniParser(lnutil.MSGID_REMOTE_RPCRESPONSE), hf) 56 mp.DefineMessage(lnutil.MSGID_PAY_REQ, makeNeoOmniParser(lnutil.MSGID_PAY_REQ), hf) 57 mp.DefineMessage(lnutil.MSGID_PAY_ACK, makeNeoOmniParser(lnutil.MSGID_PAY_ACK), hf) 58 mp.DefineMessage(lnutil.MSGID_PAY_SETUP, makeNeoOmniParser(lnutil.MSGID_PAY_SETUP), hf) 59 60 } 61 62 // handles stuff that comes in over the wire. Not user-initiated. 63 func (nd *LitNode) PeerHandler(msg lnutil.LitMsg, q *Qchan, peer *RemotePeer) error { 64 logging.Infof("Message from %d type %x", msg.Peer(), msg.MsgType()) 65 switch msg.MsgType() & 0xf0 { 66 case 0x00: // TEXT MESSAGE. SIMPLE 67 chat, ok := msg.(lnutil.ChatMsg) 68 if !ok { 69 return fmt.Errorf("can't cast to chat message") 70 } 71 nd.UserMessageBox <- fmt.Sprintf( 72 "\nmsg from %s: %s", lnutil.White(msg.Peer()), lnutil.Green(chat.Text)) 73 return nil // no error 74 75 case 0x10: //Making Channel, or using 76 return nd.ChannelHandler(msg, peer) 77 78 case 0x20: //Closing 79 return nd.CloseHandler(msg) 80 81 case 0x30: //PushPull 82 if q == nil { 83 return fmt.Errorf("pushpull message but no matching channel") 84 } 85 return nd.PushPullHandler(msg, q) 86 87 /* not yet implemented 88 case 0x40: 89 return nd.FWDHandler(msg) 90 */ 91 /* not yet implemented 92 case 0x50: 93 return nd.SelfPushHandler(msg) 94 */ 95 96 case 0x60: //Tower Messages 97 if msg.MsgType() == lnutil.MSGID_WATCH_DESC { 98 return nd.Tower.NewChannel(msg.(lnutil.WatchDescMsg)) 99 } 100 if msg.MsgType() == lnutil.MSGID_WATCH_STATEMSG { 101 return nd.Tower.UpdateChannel(msg.(lnutil.WatchStateMsg)) 102 } 103 if msg.MsgType() == lnutil.MSGID_WATCH_DELETE { 104 return nd.Tower.DeleteChannel(msg.(lnutil.WatchDelMsg)) 105 } 106 107 case 0x70: // Routing messages 108 if msg.MsgType() == lnutil.MSGID_LINK_DESC { 109 nd.LinkMsgHandler(msg.(lnutil.LinkMsg)) 110 } 111 if msg.MsgType() == lnutil.MSGID_PAY_REQ { 112 return nd.MultihopPaymentRequestHandler(msg.(lnutil.MultihopPaymentRequestMsg)) 113 } 114 if msg.MsgType() == lnutil.MSGID_PAY_ACK { 115 return nd.MultihopPaymentAckHandler(msg.(lnutil.MultihopPaymentAckMsg)) 116 } 117 if msg.MsgType() == lnutil.MSGID_PAY_SETUP { 118 return nd.MultihopPaymentSetupHandler(msg.(lnutil.MultihopPaymentSetupMsg)) 119 } 120 121 case 0xA0: // Dual Funding messages 122 return nd.DualFundingHandler(msg, peer) 123 124 case 0x90: // Discreet log contract messages 125 if msg.MsgType() == lnutil.MSGID_DLC_OFFER { 126 nd.DlcOfferHandler(msg.(lnutil.DlcOfferMsg), peer) 127 } 128 if msg.MsgType() == lnutil.MSGID_DLC_ACCEPTOFFER { 129 return nd.DlcAcceptHandler(msg.(lnutil.DlcOfferAcceptMsg), peer) 130 } 131 if msg.MsgType() == lnutil.MSGID_DLC_DECLINEOFFER { 132 nd.DlcDeclineHandler(msg.(lnutil.DlcOfferDeclineMsg), peer) 133 } 134 if msg.MsgType() == lnutil.MSGID_DLC_CONTRACTACK { 135 nd.DlcContractAckHandler(msg.(lnutil.DlcContractAckMsg), peer) 136 } 137 if msg.MsgType() == lnutil.MSGID_DLC_CONTRACTFUNDINGSIGS { 138 nd.DlcFundingSigsHandler( 139 msg.(lnutil.DlcContractFundingSigsMsg), peer) 140 } 141 if msg.MsgType() == lnutil.MSGID_DLC_SIGPROOF { 142 nd.DlcSigProofHandler(msg.(lnutil.DlcContractSigProofMsg), peer) 143 } 144 145 case 0xB0: // remote control 146 if msg.MsgType() == lnutil.MSGID_REMOTE_RPCREQUEST { 147 nd.RemoteControlRequestHandler(msg.(lnutil.RemoteControlRpcRequestMsg), peer) 148 } 149 if msg.MsgType() == lnutil.MSGID_REMOTE_RPCRESPONSE { 150 nd.RemoteControlResponseHandler(msg.(lnutil.RemoteControlRpcResponseMsg), peer) 151 } 152 default: 153 return fmt.Errorf("Unknown message id byte %x &f0", msg.MsgType()) 154 155 } 156 return nil 157 } 158 159 func (nd *LitNode) PopulateQchanMap(peer *RemotePeer) error { 160 allQs, err := nd.GetAllQchans() 161 if err != nil { 162 return err 163 } 164 // initialize map 165 nd.RemoteMtx.Lock() 166 peer.QCs = make(map[uint32]*Qchan) 167 // populate from all channels (inefficient) 168 for i, q := range allQs { 169 if q.Peer() == peer.Idx { 170 peer.QCs[q.Idx()] = allQs[i] 171 } 172 } 173 nd.RemoteMtx.Unlock() 174 return nil 175 } 176 177 func (nd *LitNode) ChannelHandler(msg lnutil.LitMsg, peer *RemotePeer) error { 178 if nd.InProgDual.PeerIdx != 0 { // a dual funding is in progress 179 nd.DualFundingHandler(msg, peer) 180 return nil 181 } 182 183 switch message := msg.(type) { 184 case lnutil.PointReqMsg: // POINT REQUEST 185 logging.Infof("Got point request from %x\n", message.Peer()) 186 nd.PointReqHandler(message) 187 return nil 188 189 case lnutil.PointRespMsg: // POINT RESPONSE 190 logging.Infof("Got point response from %x\n", msg.Peer()) 191 return nd.PointRespHandler(message) 192 193 case lnutil.ChanDescMsg: // CHANNEL DESCRIPTION 194 logging.Infof("Got channel description from %x\n", msg.Peer()) 195 196 return nd.QChanDescHandler(message) 197 198 case lnutil.ChanAckMsg: // CHANNEL ACKNOWLEDGE 199 logging.Infof("Got channel acknowledgement from %x\n", msg.Peer()) 200 201 nd.QChanAckHandler(message, peer) 202 return nil 203 204 case lnutil.SigProofMsg: // HERE'S YOUR CHANNEL 205 logging.Infof("Got channel proof from %x\n", msg.Peer()) 206 nd.SigProofHandler(message, peer) 207 return nil 208 209 default: 210 return fmt.Errorf("Unknown message type %x", msg.MsgType()) 211 } 212 213 } 214 215 func (nd *LitNode) DualFundingHandler(msg lnutil.LitMsg, peer *RemotePeer) error { 216 switch message := msg.(type) { 217 case lnutil.DualFundingReqMsg: // DUAL FUNDING REQUEST 218 logging.Infof("Got dual funding request from %x\n", message.Peer()) 219 nd.DualFundingReqHandler(message) 220 return nil 221 222 case lnutil.DualFundingAcceptMsg: // DUAL FUNDING ACCEPT 223 logging.Infof("Got dual funding acceptance from %x\n", msg.Peer()) 224 nd.DualFundingAcceptHandler(message) 225 return nil 226 227 case lnutil.DualFundingDeclMsg: // DUAL FUNDING DECLINE 228 logging.Infof("Got dual funding decline from %x\n", msg.Peer()) 229 nd.DualFundingDeclHandler(message) 230 return nil 231 232 case lnutil.ChanDescMsg: // CHANNEL DESCRIPTION 233 logging.Infof("Got (dual funding) channel description from %x\n", msg.Peer()) 234 nd.DualFundChanDescHandler(message) 235 return nil 236 237 case lnutil.DualFundingChanAckMsg: // CHANNEL ACKNOWLEDGE 238 logging.Infof("Got (dual funding) channel acknowledgement from %x\n", msg.Peer()) 239 240 nd.DualFundChanAckHandler(message, peer) 241 return nil 242 243 case lnutil.SigProofMsg: // HERE'S YOUR CHANNEL 244 logging.Infof("Got (dual funding) channel proof from %x\n", msg.Peer()) 245 nd.DualFundSigProofHandler(message, peer) 246 return nil 247 248 default: 249 return fmt.Errorf("Unknown message type %x", msg.MsgType()) 250 } 251 252 } 253 254 func (nd *LitNode) CloseHandler(msg lnutil.LitMsg) error { 255 switch message := msg.(type) { // CLOSE REQ 256 257 case lnutil.CloseReqMsg: 258 logging.Infof("Got close request from %x\n", msg.Peer()) 259 nd.CloseReqHandler(message) 260 return nil 261 262 /* - not yet implemented 263 case lnutil.MSGID_CLOSERESP: // CLOSE RESP 264 logging.Infof("Got close response from %x\n", from) 265 nd.CloseRespHandler(from, msg[1:]) 266 continue 267 return nil 268 */ 269 default: 270 return fmt.Errorf("Unknown message type %x", msg.MsgType()) 271 } 272 273 } 274 275 // need a go routine for each qchan. 276 277 func (nd *LitNode) PushPullHandler(routedMsg lnutil.LitMsg, q *Qchan) error { 278 q.ChanMtx.Lock() 279 defer q.ChanMtx.Unlock() 280 switch message := routedMsg.(type) { 281 case lnutil.DeltaSigMsg: 282 logging.Infof("Got DELTASIG from %x\n", routedMsg.Peer()) 283 return nd.DeltaSigHandler(message, q) 284 285 case lnutil.SigRevMsg: // SIGNATURE AND REVOCATION 286 logging.Infof("Got SIGREV from %x\n", routedMsg.Peer()) 287 return nd.SigRevHandler(message, q) 288 289 case lnutil.GapSigRevMsg: // GAP SIGNATURE AND REVOCATION 290 logging.Infof("Got GapSigRev from %x\n", routedMsg.Peer()) 291 return nd.GapSigRevHandler(message, q) 292 293 case lnutil.RevMsg: // REVOCATION 294 logging.Infof("Got REV from %x\n", routedMsg.Peer()) 295 return nd.RevHandler(message, q) 296 297 case lnutil.HashSigMsg: // Offer HTLC 298 logging.Infof("Got HashSig from %d", routedMsg.Peer()) 299 return nd.HashSigHandler(message, q) 300 301 case lnutil.PreimageSigMsg: // Clear HTLC 302 logging.Infof("Got PreimageSig from %d", routedMsg.Peer()) 303 return nd.PreimageSigHandler(message, q) 304 305 default: 306 return fmt.Errorf("Unknown message type %x", routedMsg.MsgType()) 307 308 } 309 310 } 311 312 func (nd *LitNode) FWDHandler(msg lnutil.LitMsg) error { // not yet implemented 313 switch message := msg.(type) { 314 default: 315 return fmt.Errorf("Unknown message type %x", message.MsgType()) 316 } 317 } 318 319 func (nd *LitNode) SelfPushHandler(msg lnutil.LitMsg) error { // not yet implemented 320 switch message := msg.(type) { 321 default: 322 return fmt.Errorf("Unknown message type %x", message.MsgType()) 323 } 324 } 325 326 // OPEventHandler gets outpoint events from the base wallet, 327 // and modifies the ln node db to reflect confirmations. Can also respond 328 // with exporting txos to the base wallet, or penalty txs. 329 func (nd *LitNode) OPEventHandler(OPEventChan chan lnutil.OutPointEvent) { 330 for { 331 curOPEvent := <-OPEventChan 332 // get all channels each time. This is very inefficient! 333 qcs, err := nd.GetAllQchans() 334 if err != nil { 335 logging.Errorf("ln db error: %s", err.Error()) 336 continue 337 } 338 var theQ *Qchan 339 for _, q := range qcs { 340 if lnutil.OutPointsEqual(q.Op, curOPEvent.Op) { 341 theQ = q 342 } 343 } 344 345 var theC *lnutil.DlcContract 346 347 if theQ == nil { 348 // Check if this is a contract output 349 contracts, err := nd.DlcManager.ListContracts() 350 if err != nil { 351 logging.Errorf("contract db error: %s\n", err.Error()) 352 continue 353 } 354 for _, c := range contracts { 355 if lnutil.OutPointsEqual(c.FundingOutpoint, curOPEvent.Op) { 356 theC = c 357 } 358 } 359 } 360 361 if theC != nil { 362 err := nd.HandleContractOPEvent(theC, &curOPEvent) 363 if err != nil { 364 logging.Errorf("HandleContractOPEvent error: %s\n", err.Error()) 365 } 366 continue 367 } 368 369 if theQ == nil && curOPEvent.Tx != nil { 370 // Check if this is a HTLC output we're watching 371 h, _, err := nd.GetHTLC(&curOPEvent.Op) 372 if err != nil { 373 logging.Errorf("Error Getting HTLC OPHash: %s\n", err.Error()) 374 } 375 if h.Idx == 0 && h.Amt == 0 { // empty HTLC, so none found 376 continue 377 } 378 379 logging.Infof("Got OP event for HTLC output %s [Incoming: %t]\n", curOPEvent.Op.String(), h.Incoming) 380 // Check the witness stack for a preimage 381 for _, txi := range curOPEvent.Tx.TxIn { 382 383 var preimage [16]byte 384 preimageFound := false 385 if len(txi.Witness) == 5 && len(txi.Witness[0]) == 0 && len(txi.Witness[3]) == 16 { 386 // Success transaction from their break TX, multisig. Preimage is fourth on the witness stack. 387 copy(preimage[:], txi.Witness[3]) 388 preimageFound = true 389 } 390 if len(txi.Witness) == 3 && len(txi.Witness[1]) == 16 { 391 // Success transaction from their break TX, multisig. Preimage is fourth on the witness stack. 392 copy(preimage[:], txi.Witness[1]) 393 preimageFound = true 394 } 395 396 if preimageFound { 397 logging.Infof("Found preimage [%x] in this TX, looking for HTLCs i have that are claimable with that\n", preimage) 398 // try claiming it! 399 nd.ClaimHTLC(preimage) 400 } 401 } 402 403 continue 404 } 405 406 // end if no associated channel 407 if theQ == nil { 408 logging.Infof("OPEvent %s doesn't match any channel\n", 409 curOPEvent.Op.String()) 410 continue 411 } 412 413 // confirmation event 414 if curOPEvent.Tx == nil { 415 logging.Infof("OP %s Confirmation event\n", curOPEvent.Op.String()) 416 theQ.Height = curOPEvent.Height 417 err = nd.SaveQchanUtxoData(theQ) 418 if err != nil { 419 logging.Errorf("SaveQchanUtxoData error: %s", err.Error()) 420 continue 421 } 422 // spend event (note: happens twice!) 423 424 if theQ.Height > 0 { 425 logging.Debugf("Second time this is confirmed, send out real confirm event") 426 427 // TODO: abstract important channel things into a channel manager type of thing 428 peerIdx := theQ.Peer() 429 peer := nd.PeerMan.GetPeerByIdx(int32(peerIdx)) 430 if peer == nil { 431 logging.Errorf("Please use errors in peermanager rather than just returning could be nil or 0 or something else") 432 } else { 433 confirmEvent := ChannelStateUpdateEvent{ 434 Action: "opconfirm", 435 ChanIdx: theQ.Idx(), 436 State: theQ.State, 437 TheirPub: peer.GetPubkey(), 438 CoinType: theQ.Coin(), 439 } 440 441 if succeed, err := nd.Events.Publish(confirmEvent); err != nil { 442 logging.Errorf("ConfirmHandler publish err %s", err) 443 return 444 } else if !succeed { 445 logging.Errorf("ConfirmHandler publish did not succeed") 446 return 447 } 448 } 449 } 450 451 } else { 452 logging.Infof("OP %s Spend event\n", curOPEvent.Op.String()) 453 // mark channel as closed 454 theQ.CloseData.Closed = true 455 theQ.CloseData.CloseTxid = curOPEvent.Tx.TxHash() 456 theQ.CloseData.CloseHeight = curOPEvent.Height 457 err = nd.SaveQchanUtxoData(theQ) 458 if err != nil { 459 logging.Errorf("SaveQchanUtxoData error: %s", err.Error()) 460 continue 461 } 462 463 // detect close tx outs. 464 txos, err := theQ.GetCloseTxos(curOPEvent.Tx) 465 if err != nil { 466 logging.Errorf("GetCloseTxos error: %s", err.Error()) 467 continue 468 } 469 470 // if you have seq=1 txos, modify the privkey... 471 // pretty ugly as we need the private key to do that. 472 for _, ptxo := range txos { 473 if ptxo.Seq == 1 { // revoked key 474 // GetCloseTxos returns a porTxo with the elk scalar in the 475 // privkey field. It isn't just added though; it needs to 476 // be combined with the private key in a way porTxo isn't 477 // aware of, so derive and subtract that here. 478 var elkScalar [32]byte 479 // swap out elkscalar, leaving privkey empty 480 elkScalar, ptxo.KeyGen.PrivKey = 481 ptxo.KeyGen.PrivKey, elkScalar 482 483 privBase, err := nd.SubWallet[theQ.Coin()].GetPriv(ptxo.KeyGen) 484 if err != nil { 485 continue // or return? 486 } 487 488 ptxo.PrivKey = lnutil.CombinePrivKeyAndSubtract( 489 privBase, elkScalar[:]) 490 } 491 // make this concurrent to avoid circular locking 492 go func(porTxo portxo.PorTxo) { 493 nd.SubWallet[theQ.Coin()].ExportUtxo(&porTxo) 494 }(ptxo) 495 } 496 497 // Fetch the indexes of HTLC outputs, and then register them to be watched 498 // We can monitor this for spends from an HTLC output that contains a preimage 499 // and then use that preimage to claim any HTLCs we have outstanding. 500 _, htlcIdxes, err := theQ.GetHtlcTxos(curOPEvent.Tx, false) 501 if err != nil { 502 logging.Errorf("GetHtlcTxos error: %s", err.Error()) 503 continue 504 } 505 _, htlcOurIdxes, err := theQ.GetHtlcTxos(curOPEvent.Tx, true) 506 if err != nil { 507 logging.Errorf("GetHtlcTxos error: %s", err.Error()) 508 continue 509 } 510 htlcIdxes = append(htlcIdxes, htlcOurIdxes...) 511 txHash := curOPEvent.Tx.TxHash() 512 for _, i := range htlcIdxes { 513 op := wire.NewOutPoint(&txHash, i) 514 logging.Infof("Watching for spends from [%s] (HTLC)\n", op.String()) 515 nd.SubWallet[theQ.Coin()].WatchThis(*op) 516 } 517 } 518 } 519 } 520 521 func (nd *LitNode) HeightEventHandler(HeightEventChan chan lnutil.HeightEvent) { 522 for { 523 event := <-HeightEventChan 524 txs, err := nd.ClaimHTLCTimeouts(event.CoinType, event.Height) 525 if err != nil { 526 logging.Errorf("Error while claiming HTLC timeouts for coin %d at height %d : %s\n", event.CoinType, event.Height, err.Error()) 527 } else { 528 for _, tx := range txs { 529 logging.Infof("Claimed timeout HTLC using TXID %x\n", tx) 530 } 531 } 532 } 533 } 534 535 func (nd *LitNode) HandleContractOPEvent(c *lnutil.DlcContract, 536 opEvent *lnutil.OutPointEvent) error { 537 538 logging.Infof("Received OPEvent for contract %d!\n", c.Idx) 539 if opEvent.Tx != nil { 540 wal, ok := nd.SubWallet[c.CoinType] 541 if !ok { 542 return fmt.Errorf("Could not find associated wallet"+ 543 " for type %d", c.CoinType) 544 } 545 546 pkhIsMine := false 547 pkhIdx := uint32(0) 548 value := int64(0) 549 myPKHPkSript := lnutil.DirectWPKHScriptFromPKH(c.OurPayoutPKH) 550 for i, out := range opEvent.Tx.TxOut { 551 if bytes.Equal(myPKHPkSript, out.PkScript) { 552 pkhIdx = uint32(i) 553 pkhIsMine = true 554 value = out.Value 555 } 556 } 557 558 if pkhIsMine { 559 c.Status = lnutil.ContractStatusSettling 560 err := nd.DlcManager.SaveContract(c) 561 if err != nil { 562 logging.Errorf("HandleContractOPEvent SaveContract err %s\n", err.Error()) 563 return err 564 } 565 566 // We need to claim this. 567 txClaim := wire.NewMsgTx() 568 txClaim.Version = 2 569 570 settleOutpoint := wire.OutPoint{Hash: opEvent.Tx.TxHash(), Index: pkhIdx} 571 txClaim.AddTxIn(wire.NewTxIn(&settleOutpoint, nil, nil)) 572 573 addr, err := wal.NewAdr() 574 if err != nil { 575 return err 576 } 577 txClaim.AddTxOut(wire.NewTxOut(value-500, 578 lnutil.DirectWPKHScriptFromPKH(addr))) // todo calc fee 579 580 var kg portxo.KeyGen 581 kg.Depth = 5 582 kg.Step[0] = 44 | 1<<31 583 kg.Step[1] = c.CoinType | 1<<31 584 kg.Step[2] = UseContractPayoutPKH 585 kg.Step[3] = c.PeerIdx | 1<<31 586 kg.Step[4] = uint32(c.Idx) | 1<<31 587 priv, _ := wal.GetPriv(kg) 588 589 // make hash cache 590 hCache := txscript.NewTxSigHashes(txClaim) 591 592 // generate sig 593 txClaim.TxIn[0].Witness, err = txscript.WitnessScript(txClaim, 594 hCache, 0, value, myPKHPkSript, txscript.SigHashAll, priv, true) 595 596 if err != nil { 597 return err 598 } 599 wal.DirectSendTx(txClaim) 600 601 c.Status = lnutil.ContractStatusClosed 602 err = nd.DlcManager.SaveContract(c) 603 if err != nil { 604 return err 605 } 606 } 607 608 } 609 return nil 610 }