forked from chappjc/dcrspy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtxhelpers.go
178 lines (148 loc) · 4.51 KB
/
txhelpers.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// txhelpers.go contains helper functions for working with transactions and
// blocks (e.g. checking for a transaction in a block).
package main
import (
"sort"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrutil"
"github.com/decred/dcrd/rpcclient"
"github.com/decred/dcrd/txscript"
"github.com/decred/dcrd/wire"
)
// TxAction is what is happening to the transaction (mined or inserted into
// mempool).
type TxAction int32
// Valid values for TxAction
const (
TxMined TxAction = 1 << iota
TxInserted
// removed? invalidated?
)
func TxhashInSlice(txs []*dcrutil.Tx, txHash *chainhash.Hash) *dcrutil.Tx {
if len(txs) < 1 {
return nil
}
for _, minedTx := range txs {
txSha := minedTx.Hash()
if txHash.IsEqual(txSha) {
return minedTx
}
}
return nil
}
// includesStakeTx checks if a block contains a stake transaction hash
func IncludesStakeTx(txHash *chainhash.Hash, block *dcrutil.Block) (int, int8) {
blockTxs := block.STransactions()
if tx := TxhashInSlice(blockTxs, txHash); tx != nil {
return tx.Index(), tx.Tree()
}
return -1, -1
}
// includesTx checks if a block contains a transaction hash
func IncludesTx(txHash *chainhash.Hash, block *dcrutil.Block) (int, int8) {
blockTxs := block.Transactions()
if tx := TxhashInSlice(blockTxs, txHash); tx != nil {
return tx.Index(), tx.Tree()
}
return -1, -1
}
func blockConsumesOutpointWithAddresses(block *dcrutil.Block, addrs map[string]TxAction,
c *rpcclient.Client) map[string][]*dcrutil.Tx {
addrMap := make(map[string][]*dcrutil.Tx)
checkForOutpointAddr := func(blockTxs []*dcrutil.Tx) {
for _, tx := range blockTxs {
for _, txIn := range tx.MsgTx().TxIn {
prevOut := &txIn.PreviousOutPoint
// For each TxIn, check the indicated vout index in the txid of the
// previous outpoint.
// txrr, err := c.GetRawTransactionVerbose(&prevOut.Hash)
prevTx, err := c.GetRawTransaction(&prevOut.Hash)
if err != nil {
log.Debug("Unable to get raw transaction for ", prevOut.Hash.String())
continue
}
// prevOut.Index should tell us which one, but check all anyway
for _, txOut := range prevTx.MsgTx().TxOut {
_, txAddrs, _, err := txscript.ExtractPkScriptAddrs(
txOut.Version, txOut.PkScript, activeChain)
if err != nil {
log.Infof("ExtractPkScriptAddrs: %v", err.Error())
continue
}
for _, txAddr := range txAddrs {
addrstr := txAddr.EncodeAddress()
if _, ok := addrs[addrstr]; ok {
if addrMap[addrstr] == nil {
addrMap[addrstr] = make([]*dcrutil.Tx, 0)
}
addrMap[addrstr] = append(addrMap[addrstr], prevTx)
}
}
}
}
}
}
checkForOutpointAddr(block.Transactions())
checkForOutpointAddr(block.STransactions())
return addrMap
}
// BlockReceivesToAddresses checks a block for transactions paying to the
// specified addresses, and creates a map of addresses to a slice of dcrutil.Tx
// involving the address.
func BlockReceivesToAddresses(block *wire.MsgBlock, addrs map[string]TxAction) map[string][]*wire.MsgTx {
addrMap := make(map[string][]*wire.MsgTx)
checkForAddrOut := func(blockTxs []*wire.MsgTx) {
for _, tx := range blockTxs {
// Check the addresses associated with the PkScript of each TxOut
for _, txOut := range tx.TxOut {
_, txOutAddrs, _, err := txscript.ExtractPkScriptAddrs(txOut.Version,
txOut.PkScript, activeChain)
if err != nil {
log.Infof("ExtractPkScriptAddrs: %v", err.Error())
continue
}
// Check if we are watching any address for this TxOut
for _, txAddr := range txOutAddrs {
addrstr := txAddr.EncodeAddress()
if _, ok := addrs[addrstr]; ok {
if _, gotSlice := addrMap[addrstr]; !gotSlice {
addrMap[addrstr] = make([]*wire.MsgTx, 0) // nil
}
addrMap[addrstr] = append(addrMap[addrstr], tx)
}
}
}
}
}
checkForAddrOut(block.Transactions)
checkForAddrOut(block.STransactions)
return addrMap
}
// MedianAmount gets the median Amount from a slice of Amounts
func MedianAmount(s []dcrutil.Amount) dcrutil.Amount {
if len(s) == 0 {
return 0
}
sort.Sort(dcrutil.AmountSorter(s))
middle := len(s) / 2
if len(s) == 0 {
return 0
} else if (len(s) % 2) != 0 {
return s[middle]
}
return (s[middle] + s[middle-1]) / 2
}
// MedianCoin gets the median DCR from a slice of float64s
func MedianCoin(s []float64) float64 {
if len(s) == 0 {
return 0
}
sort.Float64s(s)
middle := len(s) / 2
if len(s) == 0 {
return 0
} else if (len(s) % 2) != 0 {
return s[middle]
}
return (s[middle] + s[middle-1]) / 2
}