github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/qln/lndb.go (about) 1 package qln 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "sync" 8 "time" 9 10 "github.com/boltdb/bolt" 11 "github.com/mit-dci/lit/crypto/koblitz" 12 "github.com/mit-dci/lit/dlc" 13 "github.com/mit-dci/lit/eventbus" 14 "github.com/mit-dci/lit/lncore" 15 "github.com/mit-dci/lit/lndc" 16 "github.com/mit-dci/lit/lnp2p" 17 "github.com/mit-dci/lit/lnutil" 18 "github.com/mit-dci/lit/logging" 19 "github.com/mit-dci/lit/watchtower" 20 "github.com/mit-dci/lit/wire" 21 ) 22 23 /* 24 Channels (& multisig) go in the DB here. 25 first there's the peer bucket. 26 27 Here's the structure: 28 29 Peers 30 | 31 |- peerID (33 byte pubkey) 32 | 33 |- index (4 bytes) 34 | 35 |- hostname...? 36 | 37 |- channels..? 38 39 40 PeerMap 41 | 42 |-peerIdx(4) : peerPubkey(33) 43 44 ChannelMap 45 | 46 |-chanIdx(4) : channelID (36 byte outpoint) 47 48 49 Right now these buckets are all in one boltDB. This limits it to one db write 50 at a time, which for super high thoughput could be too slow. 51 Later on we can chop it up so that each channel gets it's own db file. 52 53 54 MultiWallit: 55 56 One LitNode can have a bunch of SubWallets. This is useful if you want to 57 have both testnet3 and regtest channels active simultaneously. 58 The SubWallet is a map of uint32s to Uwallet interfaces. The identifier for the 59 channel is the coin's HDCoinType, which is available from the params. 60 61 I said regtest is 257 because it's not defined in a BIP, and set to 1 62 (collision w/ testnet3) in the btcsuite code. 63 64 Other coins could use SLIP-44, which will be IPV4 all over again as people 65 make millions of pointless altcoins to grab that address space. 66 67 Since usually there is only 1 wallit connected, there is a DefaultWallet 68 which functions can use if the wallet is not specified. The first wallet 69 to get attached to DefaultWallet. There is also a bool MultiWallet which is 70 false while there is only 1 wallet, and true once there are more than one 71 wallets connected. 72 73 You can't remove wallets once they're attached; just restart instead. 74 75 */ 76 77 // LitNode is the main struct for the node, keeping track of all channel state and 78 // communicating with the underlying UWallet 79 type LitNode struct { 80 LitDB *bolt.DB // place to write all this down 81 82 NewLitDB lncore.LitStorage 83 84 LitFolder string // path to save stuff 85 86 IdentityKey *koblitz.PrivateKey 87 88 // p2p remote control key 89 DefaultRemoteControlKey *koblitz.PublicKey 90 91 // event bus 92 Events *eventbus.EventBus 93 94 // Networking 95 PeerMan *lnp2p.PeerManager 96 97 // all nodes have a watchtower. but could have a tower without a node 98 Tower watchtower.Watcher 99 100 // discreet log contract manager 101 DlcManager *dlc.DlcManager 102 103 // BaseWallet is the underlying wallet which keeps track of utxos, secrets, 104 // and network i/o 105 // map of cointypes to wallets 106 SubWallet map[uint32]UWallet 107 // indicates if multiple wallets are connected 108 MultiWallet bool 109 // cointype of the first (possibly only) wallet connected 110 DefaultCoin uint32 111 112 ConnectedCoinTypes map[uint32]bool 113 RemoteCons map[uint32]*RemotePeer 114 RemoteMtx sync.Mutex 115 116 // the current channel that in the process of being created 117 // (1 at a time for now) 118 InProg *InFlightFund 119 120 // the current channel in process of being dual funded 121 InProgDual *InFlightDualFund 122 123 // Nodes don't have Params; their SubWallets do 124 // Param *coinparam.Params // network parameters (testnet3, segnet, etc) 125 126 // queue for async messages to RPC user 127 UserMessageBox chan string 128 129 // The URL from which lit attempts to resolve the LN address 130 TrackerURL string 131 132 ChannelMap map[[20]byte][]LinkDesc 133 ChannelMapMtx sync.Mutex 134 AdvTimeout *time.Ticker 135 136 RPC interface{} 137 138 // Contains the URL string to connect to a SOCKS5 proxy, if provided 139 ProxyURL string 140 Nat string 141 142 InProgMultihop []*InFlightMultihop 143 MultihopMutex sync.Mutex 144 145 ExchangeRates map[uint32][]lnutil.RateDesc 146 147 // REFACTORING FIELDS 148 PeerMap map[*lnp2p.Peer]*RemotePeer // we never remove things from here, so this is a memory leak 149 PeerMapMtx *sync.Mutex 150 } 151 152 type LinkDesc struct { 153 Link lnutil.LinkMsg 154 Dirty bool 155 } 156 157 type InFlightMultihop struct { 158 Path []lnutil.RouteHop 159 Amt int64 160 HHash [32]byte 161 PreImage [16]byte 162 Succeeded bool 163 } 164 165 func (p *InFlightMultihop) Bytes() []byte { 166 var buf bytes.Buffer 167 168 wire.WriteVarInt(&buf, 0, uint64(len(p.Path))) 169 for _, nd := range p.Path { 170 buf.Write(nd.Bytes()) 171 } 172 173 wire.WriteVarInt(&buf, 0, uint64(p.Amt)) 174 175 buf.Write(p.HHash[:]) 176 buf.Write(p.PreImage[:]) 177 178 binary.Write(&buf, binary.BigEndian, p.Succeeded) 179 180 return buf.Bytes() 181 } 182 183 func InFlightMultihopFromBytes(b []byte) (*InFlightMultihop, error) { 184 mh := new(InFlightMultihop) 185 186 buf := bytes.NewBuffer(b) // get rid of messageType 187 188 hops, _ := wire.ReadVarInt(buf, 0) 189 for i := uint64(0); i < hops; i++ { 190 hop, err := lnutil.NewRouteHopFromBytes(buf.Next(24)) 191 if err != nil { 192 return nil, err 193 } 194 195 mh.Path = append(mh.Path, *hop) 196 } 197 amount, _ := wire.ReadVarInt(buf, 0) 198 mh.Amt = int64(amount) 199 200 copy(mh.HHash[:], buf.Next(32)) 201 copy(mh.PreImage[:], buf.Next(16)) 202 203 err := binary.Read(buf, binary.BigEndian, &mh.Succeeded) 204 if err != nil { 205 return mh, err 206 } 207 208 return mh, nil 209 } 210 211 type RemotePeer struct { 212 Idx uint32 // the peer index 213 Nickname string 214 Con *lndc.Conn 215 QCs map[uint32]*Qchan // keep map of all peer's channels in ram 216 OpMap map[[36]byte]uint32 // quick lookup for channels 217 } 218 219 // InFlightFund is a funding transaction that has not yet been broadcast 220 type InFlightFund struct { 221 PeerIdx, ChanIdx, Coin uint32 222 Amt, InitSend int64 223 224 op *wire.OutPoint 225 226 done chan uint32 227 // use this to avoid crashiness 228 mtx sync.Mutex 229 230 Data [32]byte 231 } 232 233 func (inff *InFlightFund) Clear() { 234 inff.PeerIdx = 0 235 inff.ChanIdx = 0 236 237 inff.Amt = 0 238 inff.InitSend = 0 239 } 240 241 // InFlightDualFund is a dual funding transaction that has not yet been broadcast 242 type InFlightDualFund struct { 243 PeerIdx, ChanIdx, CoinType uint32 244 OurAmount, TheirAmount int64 245 OurInputs, TheirInputs []lnutil.DualFundingInput 246 OurChangeAddress, TheirChangeAddress [20]byte 247 OurPub, OurRefundPub, OurHAKDBase [33]byte 248 TheirPub, TheirRefundPub, TheirHAKDBase [33]byte 249 OurNextHTLCBase, OurN2HTLCBase [33]byte 250 TheirNextHTLCBase, TheirN2HTLCBase [33]byte 251 OurSignatures, TheirSignatures [][60]byte 252 InitiatedByUs bool 253 OutPoint *wire.OutPoint 254 done chan *DualFundingResult 255 mtx sync.Mutex 256 } 257 258 type DualFundingResult struct { 259 ChannelId uint32 260 Error bool 261 Accepted bool 262 DeclineReason uint8 263 } 264 265 func (inff *InFlightDualFund) Clear() { 266 inff.PeerIdx = 0 267 inff.ChanIdx = 0 268 inff.OurAmount = 0 269 inff.TheirAmount = 0 270 inff.OurInputs = nil 271 inff.TheirInputs = nil 272 inff.OurChangeAddress = [20]byte{} 273 inff.TheirChangeAddress = [20]byte{} 274 inff.OurPub = [33]byte{} 275 inff.OurRefundPub = [33]byte{} 276 inff.OurHAKDBase = [33]byte{} 277 inff.TheirPub = [33]byte{} 278 inff.TheirRefundPub = [33]byte{} 279 inff.TheirHAKDBase = [33]byte{} 280 inff.OurNextHTLCBase = [33]byte{} 281 inff.OurN2HTLCBase = [33]byte{} 282 inff.TheirNextHTLCBase = [33]byte{} 283 inff.TheirN2HTLCBase = [33]byte{} 284 285 inff.OurSignatures = nil 286 inff.TheirSignatures = nil 287 inff.InitiatedByUs = false 288 } 289 290 // GetLnAddr gets the lightning address for this node. 291 func (nd *LitNode) GetLnAddr() string { 292 return nd.PeerMan.GetExternalAddress() 293 } 294 295 // GetPubHostFromPeerIdx gets the pubkey and internet host name for a peer 296 func (nd *LitNode) GetPubHostFromPeerIdx(idx uint32) ([33]byte, string) { 297 var pub [33]byte 298 var host string 299 300 p := nd.PeerMan.GetPeerByIdx(int32(idx)) 301 if p != nil { 302 pk := p.GetPubkey() 303 copy(pub[:], pk.SerializeCompressed()) 304 host = p.GetRemoteAddr() 305 } 306 307 return pub, host 308 } 309 310 // GetNicknameFromPeerIdx gets the nickname for a peer 311 func (nd *LitNode) GetNicknameFromPeerIdx(idx uint32) string { 312 var nickname string 313 314 p := nd.PeerMan.GetPeerByIdx(int32(idx)) 315 if p != nil { 316 nickname = p.GetNickname() 317 } 318 319 return nickname 320 } 321 322 // NextIdx returns the next channel index to use. 323 func (nd *LitNode) NextChannelIdx() (uint32, error) { 324 var cIdx uint32 325 err := nd.LitDB.View(func(btx *bolt.Tx) error { 326 cmp := btx.Bucket(BKTChanMap) 327 if cmp == nil { 328 return fmt.Errorf("NextIdxForPeer: no ChanMap") 329 } 330 331 cIdx = uint32(cmp.Stats().KeyN + 1) 332 return nil 333 }) 334 if err != nil { 335 return 0, err 336 } 337 338 return cIdx, nil 339 } 340 341 // SaveNicknameForPeerIdx saves/overwrites a nickname for a given peer idx 342 func (nd *LitNode) SaveNicknameForPeerIdx(nickname string, idx uint32) error { 343 344 peer := nd.PeerMan.GetPeerByIdx(int32(idx)) 345 if peer == nil { 346 return fmt.Errorf("invalid peer ID %d", idx) 347 } 348 349 // Actually go and set it. 350 pi := peer.IntoPeerInfo() 351 err := nd.NewLitDB.GetPeerDB().AddPeer(peer.GetLnAddr(), pi) 352 353 return err // same as if err != nil { return err } ; return nil 354 } 355 356 // SaveQchanUtxoData saves utxo data such as outpoint and close tx / status. 357 func (nd *LitNode) SaveQchanUtxoData(q *Qchan) error { 358 logging.Warnln("someone tried to SaveQchanUtxoData, doing some hacks to make it save only parts of it") 359 360 // XXX This is a horrible hack and we need to change other code to not be 361 // dependent on the way this data is saved/loaded. 362 opArr := lnutil.OutPointToBytes(q.Op) 363 fq, err := nd.GetQchan(opArr) 364 if err != nil { 365 return nil 366 } 367 fq.PorTxo = q.PorTxo 368 369 // we also quietly save close data when we call this function 370 if q.CloseData.Closed { 371 fq.CloseData = q.CloseData 372 } 373 374 return nd.SaveQChan(fq) 375 } 376 377 // register a new Qchan in the db 378 func (nd *LitNode) SaveQChan(q *Qchan) error { 379 if q == nil { 380 return fmt.Errorf("SaveQChan: nil qchan") 381 } 382 383 opArr := lnutil.OutPointToBytes(q.Op) 384 cIdBytes := lnutil.U32tB(q.Idx()) 385 386 qdata := nd.QchanSerializeToBytes(q) 387 388 // save channel to db. It has no state, and has no outpoint yet 389 err := nd.LitDB.Update(func(btx *bolt.Tx) error { 390 var err error 391 392 cdb := btx.Bucket(BKTChannelData) 393 if cdb == nil { 394 return fmt.Errorf("channel data bucket not found") 395 } 396 397 cmb := btx.Bucket(BKTChanMap) 398 if cmb == nil { 399 return fmt.Errorf("channel map bucket not found") 400 } 401 402 // Save both the channel... 403 err = cdb.Put(opArr[:], qdata) 404 if err != nil { 405 return err 406 } 407 408 // ...and the channel ID mapping. 409 err = cmb.Put(cIdBytes[:], opArr[:]) 410 if err != nil { 411 return err 412 } 413 414 return nil 415 }) 416 if err != nil { 417 return err 418 } 419 420 return nil 421 } 422 423 // ReloadQchan loads updated data from the db into the qchan. Loads elkrem 424 // and state, but does not change qchan info itself. Faster than GetQchan() 425 // also reload the channel close state 426 func (nd *LitNode) ReloadQchanState(qc *Qchan) error { 427 opArr := lnutil.OutPointToBytes(qc.Op) 428 429 return nd.LitDB.View(func(btx *bolt.Tx) error { 430 b := btx.Bucket(BKTChannelData) 431 if b == nil { 432 return fmt.Errorf("channel data bucket not found") 433 } 434 435 buf := b.Get(opArr[:]) 436 if buf == nil { 437 return fmt.Errorf("channel not found in DB") 438 } 439 return nd.QchanUpdateFromBytes(qc, buf) 440 }) 441 } 442 443 // Save / overwrite state of qChan in db 444 // the descent into the qchan bucket is boilerplate and it'd be nice 445 // if we can make that it's own function. Get channel bucket maybe? But then 446 // you have to close it... 447 func (nd *LitNode) SaveQchanState(q *Qchan) error { 448 logging.Warnln("someone called SaveQchanState, but this is deprecated. doing some hacks to make it save just that.") 449 450 // XXX This is a horrible hack and we need to change other code to not be 451 // dependent on the way this data is saved/loaded. 452 opArr := lnutil.OutPointToBytes(q.Op) 453 fq, err := nd.GetQchan(opArr) 454 if err != nil { 455 return nil 456 } 457 fq.State = q.State 458 459 return nd.SaveQChan(fq) 460 } 461 462 // GetAllQchans returns a slice of all channels. empty slice is OK. 463 func (nd *LitNode) GetAllQchans() ([]*Qchan, error) { 464 var qChans []*Qchan 465 err := nd.LitDB.View(func(btx *bolt.Tx) error { 466 b := btx.Bucket(BKTChannelData) 467 if b == nil { 468 return fmt.Errorf("channel data bucket not found") 469 } 470 return b.ForEach(func(_, buf []byte) error { 471 newQc, err := nd.QchanDeserializeFromBytes(buf) 472 if err != nil { 473 return err // should we not return this? 474 } 475 476 qChans = append(qChans, newQc) 477 return nil 478 }) 479 }) 480 if err != nil { 481 return nil, err 482 } 483 return qChans, nil 484 } 485 486 // GetQchan returns a single channel. 487 // pubkey and outpoint bytes. 488 func (nd *LitNode) GetQchan(opArr [36]byte) (*Qchan, error) { 489 490 var qc *Qchan 491 var err error 492 err = nd.LitDB.View(func(btx *bolt.Tx) error { 493 494 var err error 495 496 b := btx.Bucket(BKTChannelData) 497 if b == nil { 498 return fmt.Errorf("channel data bucket not found") 499 } 500 501 buf := b.Get(opArr[:]) 502 if buf == nil { 503 return fmt.Errorf("channel not found in DB") 504 } 505 506 // Go has weird scoping rules, I hope this doesn't break things. 507 qc, err = nd.QchanDeserializeFromBytes(buf) 508 if err != nil { 509 return err 510 } 511 512 return nil 513 }) 514 if err != nil { 515 return nil, err 516 } 517 518 return qc, nil 519 } 520 521 func (nd *LitNode) GetQchanOPfromIdx(cIdx uint32) ([36]byte, error) { 522 var rOp [36]byte 523 err := nd.LitDB.View(func(btx *bolt.Tx) error { 524 cmp := btx.Bucket(BKTChanMap) 525 if cmp == nil { 526 return fmt.Errorf("no channel map") 527 } 528 op := cmp.Get(lnutil.U32tB(cIdx)) 529 if op == nil { 530 return fmt.Errorf("no channel %d in db", cIdx) 531 } 532 copy(rOp[:], op) 533 return nil 534 }) 535 return rOp, err 536 } 537 538 // GetQchanByIdx is a gets the channel when you don't know the peer bytes and 539 // outpoint. Probably shouldn't have to use this if the UI is done right though. 540 func (nd *LitNode) GetQchanByIdx(cIdx uint32) (*Qchan, error) { 541 op, err := nd.GetQchanOPfromIdx(cIdx) 542 if err != nil { 543 return nil, err 544 } 545 logging.Infof("got op %x\n", op) 546 qc, err := nd.GetQchan(op) 547 if err != nil { 548 return nil, err 549 } 550 return qc, nil 551 } 552 553 // SaveMultihopPayment saves a new (or updates an existing) multihop payment in the database 554 func (nd *LitNode) SaveMultihopPayment(p *InFlightMultihop) error { 555 err := nd.LitDB.Update(func(btx *bolt.Tx) error { 556 cmp := btx.Bucket(BKTPayments) 557 if cmp == nil { 558 return fmt.Errorf("SaveMultihopPayment: no payments bucket") 559 } 560 561 // save hash : payment 562 err := cmp.Put(p.HHash[:], p.Bytes()) 563 if err != nil { 564 return err 565 } 566 567 return nil 568 }) 569 if err != nil { 570 return err 571 } 572 573 return nil 574 } 575 576 func (nd *LitNode) GetAllMultihopPayments() ([]*InFlightMultihop, error) { 577 var payments []*InFlightMultihop 578 579 err := nd.LitDB.View(func(btx *bolt.Tx) error { 580 bkt := btx.Bucket(BKTPayments) 581 if bkt == nil { 582 return fmt.Errorf("no payments bucket") 583 } 584 585 return bkt.ForEach(func(RHash []byte, paymentBytes []byte) error { 586 payment, err := InFlightMultihopFromBytes(paymentBytes) 587 if err != nil { 588 return err 589 } 590 591 // add to slice 592 payments = append(payments, payment) 593 return nil 594 }) 595 }) 596 597 return payments, err 598 }