github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/lnutil/btclib.go (about) 1 package lnutil 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "github.com/mit-dci/lit/btcutil" 9 "github.com/mit-dci/lit/btcutil/blockchain" 10 "github.com/mit-dci/lit/btcutil/txscript" 11 "github.com/mit-dci/lit/crypto/fastsha256" 12 "github.com/mit-dci/lit/wire" 13 ) 14 15 // TxAndHeight is just a tx, and the height at which it was confirmed. 16 type TxAndHeight struct { 17 Tx *wire.MsgTx 18 Height int32 19 } 20 21 // OutPointEvent is a message describing events concerning an outpoint. 22 // There's 2 event types: confirmation and spend. If the Tx pointer is nil, 23 // then it's a confirm. If the Tx has an actual MsgTx in there, it's a spend. 24 // The Height refers to either the confirmation height 25 // or the height at which it was spent. (0 means seen but unconfirmed) 26 type OutPointEvent struct { 27 Op wire.OutPoint // the outpoint being described 28 Height int32 // the height of the event 29 Tx *wire.MsgTx // the tx spending the outpoint 30 } 31 32 // HeightEvent is to inform the LN node of a new blockheight on a particular 33 // coin type. Used to detect and enforce HTLC timeouts 34 type HeightEvent struct { 35 Height int32 36 CoinType uint32 37 } 38 39 // need this because before I was comparing pointers maybe? 40 // so they were the same outpoint but stored in 2 places so false negative? 41 func OutPointsEqual(a, b wire.OutPoint) bool { 42 if !a.Hash.IsEqual(&b.Hash) { 43 return false 44 } 45 return a.Index == b.Index 46 } 47 48 /*----- serialization for tx outputs ------- */ 49 50 // outPointToBytes turns an outpoint into 36 bytes. 51 func OutPointToBytes(op wire.OutPoint) (b [36]byte) { 52 var buf bytes.Buffer 53 _, err := buf.Write(op.Hash.CloneBytes()) 54 if err != nil { 55 return 56 } 57 // write 4 byte outpoint index within the tx to spend 58 err = binary.Write(&buf, binary.BigEndian, op.Index) 59 if err != nil { 60 return 61 } 62 copy(b[:], buf.Bytes()) 63 64 return 65 } 66 67 // OutPointFromBytes gives you an outpoint from 36 bytes. 68 // since 36 is enforced, it doesn't error 69 func OutPointFromBytes(b [36]byte) *wire.OutPoint { 70 op := new(wire.OutPoint) 71 _ = op.Hash.SetBytes(b[:32]) 72 op.Index = BtU32(b[32:]) 73 return op 74 } 75 76 // P2WSHify takes a script and turns it into a 34 byte long P2WSH PkScript 77 func P2WSHify(scriptBytes []byte) []byte { 78 bldr := txscript.NewScriptBuilder() 79 bldr.AddOp(txscript.OP_0) 80 wsh := fastsha256.Sum256(scriptBytes) 81 bldr.AddData(wsh[:]) 82 b, _ := bldr.Script() // ignore script errors 83 return b 84 } 85 86 func DirectWPKHScript(pub [33]byte) []byte { 87 builder := txscript.NewScriptBuilder() 88 builder.AddOp(txscript.OP_0).AddData(btcutil.Hash160(pub[:])) 89 b, _ := builder.Script() 90 return b 91 } 92 93 func DirectWPKHScriptFromPKH(pkh [20]byte) []byte { 94 builder := txscript.NewScriptBuilder() 95 builder.AddOp(txscript.OP_0).AddData(pkh[:]) 96 b, _ := builder.Script() 97 return b 98 } 99 100 // KeyHashFromPkScript extracts the 20 or 32 byte hash from a txout PkScript 101 func KeyHashFromPkScript(pkscript []byte) []byte { 102 // match p2pkh 103 if len(pkscript) == 25 && pkscript[0] == 0x76 && pkscript[1] == 0xa9 && 104 pkscript[2] == 0x14 && pkscript[23] == 0x88 && pkscript[24] == 0xac { 105 return pkscript[3:23] 106 } 107 108 // match p2wpkh 109 if len(pkscript) == 22 && pkscript[0] == 0x00 && pkscript[1] == 0x14 { 110 return pkscript[2:] 111 } 112 113 // match p2wsh 114 if len(pkscript) == 34 && pkscript[0] == 0x00 && pkscript[1] == 0x20 { 115 return pkscript[2:] 116 } 117 118 return nil 119 } 120 121 // Not exported in txscript... so we copy and paste here 122 func PayToPubKeyHashScript(pubKeyHash []byte) ([]byte, error) { 123 return txscript.NewScriptBuilder().AddOp(txscript.OP_DUP). 124 AddOp(txscript.OP_HASH160).AddData(pubKeyHash). 125 AddOp(txscript.OP_EQUALVERIFY).AddOp(txscript.OP_CHECKSIG).Script() 126 } 127 128 // TxToString prints out some info about a transaction. for testing / debugging 129 func TxToString(tx *wire.MsgTx) string { 130 utx := btcutil.NewTx(tx) 131 str := fmt.Sprintf("size %d vsize %d wsize %d locktime %d wit: %t txid %s\n", 132 tx.SerializeSizeStripped(), blockchain.GetTxVirtualSize(utx), 133 tx.SerializeSize(), tx.LockTime, tx.HasWitness(), tx.TxHash().String()) 134 for i, in := range tx.TxIn { 135 str += fmt.Sprintf("Input %d spends %s seq %d\n", 136 i, in.PreviousOutPoint.String(), in.Sequence) 137 str += fmt.Sprintf("\tSigScript: %x\n", in.SignatureScript) 138 for j, wit := range in.Witness { 139 str += fmt.Sprintf("\twitness %d: %x\n", j, wit) 140 } 141 } 142 for i, out := range tx.TxOut { 143 if out != nil { 144 str += fmt.Sprintf("output %d script: %x amt: %d\n", 145 i, out.PkScript, out.Value) 146 } else { 147 str += fmt.Sprintf("output %d nil (WARNING)\n", i) 148 } 149 } 150 return str 151 }