github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/wallit/wallit.go (about) 1 package wallit 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "sync" 8 9 "github.com/boltdb/bolt" 10 "github.com/mit-dci/lit/btcutil" 11 "github.com/mit-dci/lit/btcutil/blockchain" 12 "github.com/mit-dci/lit/btcutil/chaincfg/chainhash" 13 "github.com/mit-dci/lit/btcutil/hdkeychain" 14 "github.com/mit-dci/lit/coinparam" 15 "github.com/mit-dci/lit/lnutil" 16 "github.com/mit-dci/lit/logging" 17 "github.com/mit-dci/lit/portxo" 18 "github.com/mit-dci/lit/uspv" 19 "github.com/mit-dci/lit/wire" 20 ) 21 22 // The Wallit is lit's main wallet struct. It's got the root key, the dbs, and 23 // contains the SPVhooks into the network. 24 type Wallit struct { 25 // could get rid of adr slice, it's just an in-ram cache... 26 StateDB *bolt.DB // place to write all this down 27 28 // Set of frozen utxos not to use... they point to the tx using em 29 FreezeSet map[wire.OutPoint]*FrozenTx 30 FreezeMutex sync.Mutex 31 32 // OPEventChan sends events to the LN wallet. 33 // Gets initialized and activates when called by qln 34 OPEventChan chan lnutil.OutPointEvent 35 36 // HeightEventChan sends block height changes to the LN wallet. 37 // Gets initialized and activates when called by qln 38 HeightEventChan chan lnutil.HeightEvent 39 40 // Params live here... 41 Param *coinparam.Params // network parameters (testnet3, segnet, etc) 42 43 // Hook is the connection to a blockchain. 44 // imports the uspv interface. Could put that somewhere else. 45 // like an interfaces library, ... lnutil? 46 Hook uspv.ChainHook 47 48 // current fee per byte 49 FeeRate int64 50 51 // From here, comes everything. It's a secret to everybody. 52 rootPrivKey *hdkeychain.ExtendedKey 53 } 54 55 type FrozenTx struct { 56 Ins []*portxo.PorTxo `json:"ins"` 57 Outs []*wire.TxOut `json:"outs"` 58 ChangeOut *wire.TxOut `json:"changeout"` 59 Nlock uint32 `json:"nlocktime"` 60 Txid chainhash.Hash `json:"txid"` 61 } 62 63 // Stxo is a utxo that has moved on. 64 type Stxo struct { 65 PorTxo portxo.PorTxo `json:"txo"` // when it used to be a utxo 66 SpendHeight int32 `json:"height"` // height at which it met its demise 67 SpendTxid chainhash.Hash `json:"txid"` // the tx that consumed it 68 } 69 70 // TxToString prints out some info about a transaction. for testing / debugging 71 func TxToString(tx *wire.MsgTx) string { 72 utx := btcutil.NewTx(tx) 73 str := fmt.Sprintf("size %d vsize %d wsize %d locktime %d wit: %t txid %s\n", 74 tx.SerializeSizeStripped(), blockchain.GetTxVirtualSize(utx), 75 tx.SerializeSize(), tx.LockTime, tx.HasWitness(), tx.TxHash().String()) 76 for i, in := range tx.TxIn { 77 str += fmt.Sprintf("Input %d spends %s seq %d\n", 78 i, in.PreviousOutPoint.String(), in.Sequence) 79 str += fmt.Sprintf("\tSigScript: %x\n", in.SignatureScript) 80 for j, wit := range in.Witness { 81 str += fmt.Sprintf("\twitness %d: %x\n", j, wit) 82 } 83 } 84 for i, out := range tx.TxOut { 85 if out != nil { 86 str += fmt.Sprintf("output %d script: %x amt: %d\n", 87 i, out.PkScript, out.Value) 88 } else { 89 str += fmt.Sprintf("output %d nil (WARNING)\n", i) 90 } 91 } 92 return str 93 } 94 95 /*----- serialization for stxos ------- */ 96 /* Stxo serialization: 97 bytelength desc at offset 98 99 53 portxo 0 100 4 sheight 53 101 32 stxid 57 102 103 end len 89 104 */ 105 106 // ToBytes turns an Stxo into some bytes. 107 // prevUtxo serialization, then spendheight [4], spendtxid [32] 108 func (s *Stxo) ToBytes() ([]byte, error) { 109 var buf bytes.Buffer 110 111 // serialize the utxo part 112 uBytes, err := s.PorTxo.Bytes() 113 if err != nil { 114 return nil, err 115 } 116 // write that into the buffer 117 _, err = buf.Write(uBytes) 118 if err != nil { 119 return nil, err 120 } 121 122 // write 4 byte height where the txo was spent 123 err = binary.Write(&buf, binary.BigEndian, s.SpendHeight) 124 if err != nil { 125 return nil, err 126 } 127 // write 32 byte txid of the spending transaction 128 _, err = buf.Write(s.SpendTxid.CloneBytes()) 129 if err != nil { 130 return nil, err 131 } 132 133 return buf.Bytes(), nil 134 } 135 136 // StxoFromBytes turns bytes into a Stxo. 137 // it's a portxo with a spendHeight and spendTxid at the end. 138 func StxoFromBytes(b []byte) (Stxo, error) { 139 var s Stxo 140 141 l := len(b) 142 if l < 96 { 143 return s, fmt.Errorf("Got %d bytes for stxo, expect a bunch", len(b)) 144 } 145 146 // last 36 bytes are height & spend txid. 147 u, err := portxo.PorTxoFromBytes(b[:l-36]) 148 if err != nil { 149 logging.Errorf(" eof? ") 150 return s, err 151 } 152 153 buf := bytes.NewBuffer(b[l-36:]) 154 // read 4 byte spend height 155 err = binary.Read(buf, binary.BigEndian, &s.SpendHeight) 156 if err != nil { 157 return s, err 158 } 159 // read 32 byte txid 160 err = s.SpendTxid.SetBytes(buf.Next(32)) 161 if err != nil { 162 return s, err 163 } 164 165 s.PorTxo = *u // assign the utxo 166 167 return s, nil 168 }