1 package util
2 3 import (
4 "bytes"
5 "io"
6 7 "github.com/p9c/p9/pkg/chainhash"
8 "github.com/p9c/p9/pkg/wire"
9 )
10 11 // TxIndexUnknown is the value returned for a transaction index that is unknown.
12 // This is typically because the transaction has not been inserted into a block
13 // yet.
14 const TxIndexUnknown = -1
15 16 // Tx defines a bitcoin transaction that provides easier and more efficient
17 // manipulation of raw transactions. It also memorizes the hash for the
18 // transaction on its first access so subsequent accesses don't have to repeat
19 // the relatively expensive hashing operations.
20 type Tx struct {
21 msgTx *wire.MsgTx // Underlying MsgTx
22 txHash *chainhash.Hash // Cached transaction hash
23 txHashWitness *chainhash.Hash // Cached transaction witness hash
24 txHasWitness *bool // If the transaction has witness data
25 txIndex int // Position within a block or TxIndexUnknown
26 }
27 28 // MsgTx returns the underlying wire.MsgTx for the transaction.
29 func (t *Tx) MsgTx() *wire.MsgTx {
30 // Return the cached transaction.
31 return t.msgTx
32 }
33 34 // Hash returns the hash of the transaction. This is equivalent to calling
35 // TxHash on the underlying wire.MsgTx, however it caches the result so
36 // subsequent calls are more efficient.
37 func (t *Tx) Hash() *chainhash.Hash {
38 // Return the cached hash if it has already been generated.
39 if t.txHash != nil {
40 return t.txHash
41 }
42 // Cache the hash and return it.
43 hash := t.msgTx.TxHash()
44 t.txHash = &hash
45 return &hash
46 }
47 48 // // WitnessHash returns the witness hash (wtxid) of the transaction. This is
49 // // equivalent to calling WitnessHash on the underlying wire.MsgTx, however it
50 // // caches the result so subsequent calls are more efficient.
51 // func (t *Tx) WitnessHash() *chainhash.Hash {
52 // // Return the cached hash if it has already been generated.
53 // if t.txHashWitness != nil {
54 // return t.txHashWitness
55 // }
56 // // Cache the hash and return it.
57 // hash := t.msgTx.WitnessHash()
58 // t.txHashWitness = &hash
59 // return &hash
60 // }
61 62 // // HasWitness returns false if none of the inputs within the transaction contain
63 // // witness data, true false otherwise. This equivalent to calling HasWitness on
64 // // the underlying wire.MsgTx, however it caches the result so subsequent calls
65 // // are more efficient.
66 // func (t *Tx) HasWitness() bool {
67 // if t.txHashWitness != nil {
68 // return *t.txHasWitness
69 // }
70 // hasWitness := t.msgTx.HasWitness()
71 // t.txHasWitness = &hasWitness
72 // return hasWitness
73 // }
74 75 // Index returns the saved index of the transaction within a block. This value
76 // will be TxIndexUnknown if it hasn't already explicitly been set.
77 func (t *Tx) Index() int {
78 return t.txIndex
79 }
80 81 // SetIndex sets the index of the transaction in within a block.
82 func (t *Tx) SetIndex(index int) {
83 t.txIndex = index
84 }
85 86 // NewTx returns a new instance of a bitcoin transaction given an underlying
87 // wire.MsgTx. See Tx.
88 func NewTx(msgTx *wire.MsgTx) *Tx {
89 return &Tx{
90 msgTx: msgTx,
91 txIndex: TxIndexUnknown,
92 }
93 }
94 95 // NewTxFromBytes returns a new instance of a bitcoin transaction given the
96 // serialized bytes. See Tx.
97 func NewTxFromBytes(serializedTx []byte) (*Tx, error) {
98 br := bytes.NewReader(serializedTx)
99 return NewTxFromReader(br)
100 }
101 102 // NewTxFromReader returns a new instance of a bitcoin transaction given a
103 // Reader to deserialize the transaction. See Tx.
104 func NewTxFromReader(r io.Reader) (*Tx, error) {
105 // Deserialize the bytes into a MsgTx.
106 var msgTx wire.MsgTx
107 e := msgTx.Deserialize(r)
108 if e != nil {
109 return nil, e
110 }
111 t := Tx{
112 msgTx: &msgTx,
113 txIndex: TxIndexUnknown,
114 }
115 return &t, nil
116 }
117