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