@@ -3,13 +3,12 @@ package gobtcsign
3
3
import (
4
4
"github.com/btcsuite/btcd/btcutil"
5
5
"github.com/btcsuite/btcd/chaincfg"
6
- "github.com/btcsuite/btcd/chaincfg/chainhash"
7
6
"github.com/btcsuite/btcd/wire"
8
7
"github.com/pkg/errors"
9
8
)
10
9
11
- // CustomParam 这是客户自定义的参数类型,表示要转入和转出的信息
12
- type CustomParam struct {
10
+ // BitcoinTxParams 这是客户自定义的参数类型,表示要转入和转出的信息
11
+ type BitcoinTxParams struct {
13
12
VinList []VinType //要转入进BTC节点的
14
13
OutList []OutType //要从BTC节点转出的-这里面通常包含1个目标(转账)和1个自己(找零)
15
14
RBFInfo RBFConfig //详见RBF机制,通常是需要启用RBF以免交易长期被卡的
@@ -22,81 +21,13 @@ type VinType struct {
22
21
RBFInfo RBFConfig //还是RBF机制,前面的是控制整个交易的,这里控制单个UTXO的
23
22
}
24
23
25
- func MustNewOutPoint (srcTxHash string , utxoIndex uint32 ) * wire.OutPoint {
26
- //which tx the utxo from.
27
- utxoHash , err := chainhash .NewHashFromStr (srcTxHash )
28
- if err != nil {
29
- panic (errors .WithMessagef (err , "wrong param utxo-from-tx-hash=%s" , srcTxHash ))
30
- }
31
- return wire .NewOutPoint (
32
- utxoHash , //这个是收到 utxo 的交易哈希,即 utxo 是从哪里来的,配合位置索引序号构成唯一索引,就能确定是花的哪个utxo
33
- utxoIndex , //这个是收到 utxo 的输出位置,比如一个交易中有多个输出,这里要选择输出的位置
34
- )
35
- }
36
-
37
24
type OutType struct {
38
25
Target AddressTuple //接收者信息,钱包地址和公钥文本,二选一填写即可
39
26
Amount int64 //聪的数量
40
27
}
41
28
42
- type AddressTuple struct {
43
- Address string //钱包地址 和 公钥脚本 二选一填写即可
44
- PkScript []byte //公钥脚本 和 钱包地址 二选一填写即可 PkScript(Public Key Script)在拼装交易和签名时使用
45
- }
46
-
47
- func NewAddressTuple (address string ) * AddressTuple {
48
- return & AddressTuple {
49
- Address : address ,
50
- PkScript : nil , //这里 address 和 pk-script 是二选一的,因此不设,在后续的逻辑里会根据地址获得 pk-script 信息
51
- }
52
- }
53
-
54
- // GetPkScript 获得公钥文本,当公钥文本存在时就用已有的,否则就根据地址计算
55
- func (one * AddressTuple ) GetPkScript (netParams * chaincfg.Params ) ([]byte , error ) {
56
- if len (one .PkScript ) > 0 {
57
- return one .PkScript , nil //假如有就直接返回,否则就根据地址计算
58
- }
59
- if one .Address == "" {
60
- return nil , errors .New ("no-pk-script-no-address" )
61
- }
62
- return GetAddressPkScript (one .Address , netParams ) //这里不用做缓存避免增加复杂度
63
- }
64
-
65
- type RBFConfig struct {
66
- AllowRBF bool //当需要RBF时需要设置,推荐启用RBF发交易,否则,当手续费过低时交易会卡在节点的内存池里
67
- Sequence uint32 //这是后来出的功能,RBF,使用更高手续费重发交易用的,当BTC交易发出到系统以后假如没人打包(手续费过低时),就可以增加手续费覆盖旧的交易
68
- }
69
-
70
- func NewRBFActive () * RBFConfig {
71
- return & RBFConfig {
72
- AllowRBF : true ,
73
- Sequence : wire .MaxTxInSequenceNum - 2 , // recommended sequence BTC推荐的默认启用RBF的就是这个数 // 选择 wire.MaxTxInSequenceNum - 2 而不是 wire.MaxTxInSequenceNum - 1 是出于一种谨慎性和规范性的考虑。虽然在技术上 wire.MaxTxInSequenceNum - 1 也可以支持 RBF,但 -2 更为常用
74
- }
75
- }
76
-
77
- func NewRBFNotUse () * RBFConfig {
78
- return & RBFConfig {
79
- AllowRBF : false , //当两个元素都为零值时表示不启用RBF机制
80
- Sequence : wire .MaxTxInSequenceNum , //当两个元素都为零值时表示不启用RBF机制,当然这里设置为 wire.MaxTxInSequenceNum 也行,逻辑已经做过判定
81
- }
82
- }
83
-
84
- func NewRBFSeqNum (sequence uint32 ) * RBFConfig {
85
- return & RBFConfig {
86
- AllowRBF : sequence != wire .MaxTxInSequenceNum , //避免设置为0被误认为是不使用RBF的
87
- Sequence : sequence ,
88
- }
89
- }
90
-
91
- func (cfg * RBFConfig ) GetSequence () uint32 {
92
- if cfg .AllowRBF || cfg .Sequence > 0 { //启用RBF机制,精确的RBF逻辑
93
- return cfg .Sequence
94
- }
95
- return wire .MaxTxInSequenceNum //当两个元素都为零值时表示不启用RBF机制-因此这里使用默认的最大值表示不启用
96
- }
97
-
98
- // GetSignParam 根据用户的输入信息拼接交易
99
- func (param * CustomParam ) GetSignParam (netParams * chaincfg.Params ) (* SignParam , error ) {
29
+ // CreateTxSignParams 根据用户的输入信息拼接交易
30
+ func (param * BitcoinTxParams ) CreateTxSignParams (netParams * chaincfg.Params ) (* SignParam , error ) {
100
31
var msgTx = wire .NewMsgTx (wire .TxVersion )
101
32
102
33
//这是发送者和发送数量的列表,很明显,这是需要签名的关键信息,现在只把待签名信息收集起来
@@ -117,7 +48,7 @@ func (param *CustomParam) GetSignParam(netParams *chaincfg.Params) (*SignParam,
117
48
return nil , errors .Errorf ("wrong tx_in.sequence default value: %v" , txIn .Sequence )
118
49
}
119
50
// 查看是否需要启用 RBF 机制
120
- if seqNo := param .GetTxInSequenceNum (input ); seqNo != wire .MaxTxInSequenceNum {
51
+ if seqNo := param .GetTxInputSequence (input ); seqNo != wire .MaxTxInSequenceNum {
121
52
txIn .Sequence = seqNo
122
53
}
123
54
msgTx .AddTxIn (txIn )
@@ -138,7 +69,7 @@ func (param *CustomParam) GetSignParam(netParams *chaincfg.Params) (*SignParam,
138
69
}, nil
139
70
}
140
71
141
- func (param * CustomParam ) GetOutputs (netParams * chaincfg.Params ) ([]* wire.TxOut , error ) {
72
+ func (param * BitcoinTxParams ) GetOutputs (netParams * chaincfg.Params ) ([]* wire.TxOut , error ) {
142
73
outputs := make ([]* wire.TxOut , 0 , len (param .OutList ))
143
74
for _ , output := range param .OutList {
144
75
pkScript , err := output .Target .GetPkScript (netParams )
@@ -150,7 +81,7 @@ func (param *CustomParam) GetOutputs(netParams *chaincfg.Params) ([]*wire.TxOut,
150
81
return outputs , nil
151
82
}
152
83
153
- func (param * CustomParam ) GetTxInSequenceNum (input VinType ) uint32 {
84
+ func (param * BitcoinTxParams ) GetTxInputSequence (input VinType ) uint32 {
154
85
// 当你确实是需要对每个交易单独设置RBF时,就可以在这里设置,单独设置到这个 vin 里面
155
86
if seqNo := input .RBFInfo .GetSequence (); seqNo != wire .MaxTxInSequenceNum { //启用RBF机制,精确的RBF逻辑
156
87
return seqNo
@@ -171,7 +102,7 @@ func (param *CustomParam) GetTxInSequenceNum(input VinType) uint32 {
171
102
}
172
103
173
104
// GetInputList 把拼交易的参数转换为验签的参数
174
- func (param * CustomParam ) GetInputList () []* VerifyTxInputParam {
105
+ func (param * BitcoinTxParams ) GetInputList () []* VerifyTxInputParam {
175
106
var inputList = make ([]* VerifyTxInputParam , 0 , len (param .VinList ))
176
107
for _ , x := range param .VinList {
177
108
inputList = append (inputList , & VerifyTxInputParam {
@@ -186,7 +117,7 @@ func (param *CustomParam) GetInputList() []*VerifyTxInputParam {
186
117
}
187
118
188
119
// GetFee 全部输入和全部输出的差额,即交易的费用
189
- func (param * CustomParam ) GetFee () btcutil.Amount {
120
+ func (param * BitcoinTxParams ) GetFee () btcutil.Amount {
190
121
var sum int64
191
122
for _ , v := range param .VinList {
192
123
sum += v .Amount
@@ -198,23 +129,18 @@ func (param *CustomParam) GetFee() btcutil.Amount {
198
129
}
199
130
200
131
// GetChangeAmountWithFee 根据交易费用计算出找零数量
201
- func (param * CustomParam ) GetChangeAmountWithFee (fee btcutil.Amount ) btcutil.Amount {
132
+ func (param * BitcoinTxParams ) GetChangeAmountWithFee (fee btcutil.Amount ) btcutil.Amount {
202
133
return param .GetFee () - fee
203
134
}
204
135
205
- func (param * CustomParam ) EstimateTxSize (netParams * chaincfg.Params , change * ChangeTo ) (int , error ) {
136
+ func (param * BitcoinTxParams ) EstimateTxSize (netParams * chaincfg.Params , change * ChangeTo ) (int , error ) {
206
137
return EstimateTxSize (param , netParams , change )
207
138
}
208
139
209
- func (param * CustomParam ) EstimateTxFee (netParams * chaincfg.Params , change * ChangeTo , feeRatePerKb btcutil.Amount , dustFee DustFee ) (btcutil.Amount , error ) {
140
+ func (param * BitcoinTxParams ) EstimateTxFee (netParams * chaincfg.Params , change * ChangeTo , feeRatePerKb btcutil.Amount , dustFee DustFee ) (btcutil.Amount , error ) {
210
141
return EstimateTxFee (param , netParams , change , feeRatePerKb , dustFee )
211
142
}
212
143
213
- // CheckMsgTxParam 当签完名以后最好是再用这个函数检查检查,避免签名逻辑在有BUG时修改输入或输出的内容
214
- func (param * CustomParam ) CheckMsgTxParam (msgTx * wire.MsgTx , netParams * chaincfg.Params ) error {
215
- return CheckMsgTxSameWithParam (msgTx , * param , netParams )
216
- }
217
-
218
144
// NewCustomParamFromMsgTx 这里提供简易的逻辑把交易的原始参数再拼回来
219
145
// 以校验参数和校验签名等信息
220
146
// 因此该函数的主要作用是校验
@@ -223,7 +149,7 @@ func (param *CustomParam) CheckMsgTxParam(msgTx *wire.MsgTx, netParams *chaincfg
223
149
// 第二个参数是设置如何获取前置输出的
224
150
// 通常是使用 客户端 请求获取前置输出,但也可以使用map把前置输出存起来,因此使用 interface 获取前置输出,提供两种实现方案
225
151
// 在项目中推荐使用 rpc 获取,这样就很方便,而在单元测试中则只需要通过 map 预先配置就行,避免网络请求也避免暴露节点配置
226
- func NewCustomParamFromMsgTx (msgTx * wire.MsgTx , preImp GetUtxoFromInterface ) (* CustomParam , error ) {
152
+ func NewCustomParamFromMsgTx (msgTx * wire.MsgTx , preImp GetUtxoFromInterface ) (* BitcoinTxParams , error ) {
227
153
var vinList = make ([]VinType , 0 , len (msgTx .TxIn ))
228
154
for _ , vin := range msgTx .TxIn {
229
155
costUtxo := vin .PreviousOutPoint
@@ -237,7 +163,7 @@ func NewCustomParamFromMsgTx(msgTx *wire.MsgTx, preImp GetUtxoFromInterface) (*C
237
163
OutPoint : * wire .NewOutPoint (& costUtxo .Hash , costUtxo .Index ),
238
164
Sender : * utxoFrom .sender ,
239
165
Amount : utxoFrom .amount ,
240
- RBFInfo : * NewRBFSeqNum (vin .Sequence ),
166
+ RBFInfo : * NewRBFConfig (vin .Sequence ),
241
167
})
242
168
}
243
169
@@ -249,7 +175,7 @@ func NewCustomParamFromMsgTx(msgTx *wire.MsgTx, preImp GetUtxoFromInterface) (*C
249
175
})
250
176
}
251
177
252
- param := & CustomParam {
178
+ param := & BitcoinTxParams {
253
179
VinList : vinList ,
254
180
OutList : outList ,
255
181
RBFInfo : * NewRBFNotUse (), //这里是不需要的,因为各个输入里将会有RBF的全部信息
@@ -258,7 +184,7 @@ func NewCustomParamFromMsgTx(msgTx *wire.MsgTx, preImp GetUtxoFromInterface) (*C
258
184
}
259
185
260
186
// VerifyMsgTxSign 使用这个检查签名是否正确
261
- func (param * CustomParam ) VerifyMsgTxSign (msgTx * wire.MsgTx , netParams * chaincfg.Params ) error {
187
+ func (param * BitcoinTxParams ) VerifyMsgTxSign (msgTx * wire.MsgTx , netParams * chaincfg.Params ) error {
262
188
inputsItem , err := param .GetVerifyTxInputsItem (netParams )
263
189
if err != nil {
264
190
return errors .WithMessage (err , "wrong get-inputs" )
@@ -269,7 +195,7 @@ func (param *CustomParam) VerifyMsgTxSign(msgTx *wire.MsgTx, netParams *chaincfg
269
195
return nil
270
196
}
271
197
272
- func (param * CustomParam ) GetVerifyTxInputsItem (netParams * chaincfg.Params ) (* VerifyTxInputsType , error ) {
198
+ func (param * BitcoinTxParams ) GetVerifyTxInputsItem (netParams * chaincfg.Params ) (* VerifyTxInputsType , error ) {
273
199
var res = & VerifyTxInputsType {
274
200
PkScripts : make ([][]byte , 0 , len (param .VinList )),
275
201
InAmounts : make ([]btcutil.Amount , 0 , len (param .VinList )),
0 commit comments