-
Notifications
You must be signed in to change notification settings - Fork 0
/
TestTx.scala
287 lines (263 loc) · 31.1 KB
/
TestTx.scala
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
package sh
import sh.ecc._
import sh.ecc.Util._
import sh.btc._
import sh.util.BytesUtil._
import sh.util.StringUtil._
import sh.util.BigIntUtil._
import sh.btc.DataStructures._
import sh.btc.BitcoinS._
import sh.util.HashUtil._
object TestTx extends App {
TestCorrectlySpendsP2PKH
TestSegWit
TestP2PKH
TestP2SH_P2PK
TestMixedOutputs
println("Tx creation and signing tests passed")
}
object TestCorrectlySpendsP2PKH {
//8efdf7b84a0f258f0f70dbfb7aba3851ef6f3fefd7958df339a7e3dbce7c4546
val randomGood = (
"02000000109cfb5f661d567f3e94fcce58b1a9dccbaeeab6b60324247ded133db2326bd224010000006a47304402207cb1857edea9558ef8d15604d2f7dedfc292c3f7a50d2d31b5a223029bb76eca02205ce9cb5ceb2b2ad1b49312f89445e63f97df89466d54c1a4e07213a773abd21f012102cbe504d85e90ec24ddf218c65a54d28d69a21e46ba138749dc5fe9d055b481d0ffffffff49b793827f976c1e0dd569f4e314aa6d41eecaf3744b13eef479c508f9c720691f0000006b483045022100d1651d02ea21f95d7bf9b3e278c0e563155d3031aeb08c8d79f917393340156102203f0987ad5e5c7d82351a3bece6862687fe44f37567e1cfc21b2b5e92f251010f012102efdfea8121169abbf9a2382cf3dfa84f49578bf91260712cc3056751f8cd86b4ffffffffd77137df7c46595bcfe55413f2f6211065795ec47804b4dd2172f56ee7ee1fa1050000006a47304402201ac3524452a931be42f80caeeab4811f2de5c0fbd545a9e640fc1941a1f6d0d8022061bfcb5c37056d13721533a7c0523953dce8168b3a352cb1079d7aec8310f59d012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775290000006a47304402206f83790ebaa994641bd734f0383f2be8d4d22865a5115dbcf29c11bfda091f570220246a456c79348355a0136ba70c21ce7e0eb4cc5878a115b6029c4c8c12320bfe012102673197289d95ee7bb0d6b7da15a052da5895da014aeafc8d7e33d9267abaebc1ffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775270000006a47304402207b675760af32baf5c3eb6275852f258639dbb70df2f7d7c189a4cc404825ede30220484439f88bc18fc9b04f92906e6750c1b873de24d6eaf09d4f70cdf148dd77ab0121036b591a9dccf916597bb1029911f90243d9dde68f51ee49bab3bf65ac57e3d641ffffffffa5fe79d9b0cb63cbd4fef34e3dec849ba23af69830b1375d2361ef204326c77a000000006a47304402200f67cb96573a16899a320cada532d4bd980071ed82e6d272b9e79b258790376c022074458f7a82259790b454274f418156c1dd69cb730c4af64d6caa5abd140f361b01210200cbb2c571e8bd14c245ff56163e157d068a3545e8f26eed980964e766b377f8ffffffff313e1a72a479df16809dfe1e239526c896d54366a075b93b6d437d115bf4664e000000006a47304402203e5ec41a0a0b5cc43802fd941a177f3c2ed2f3cdf7d16f040d374785770dcc0002204f6da5bae3db0b3b3620154d5046e4d09f577f36afcd612b031a5332006ef1f201210254dcfe791eab7d5dcb581c0f969911432b8e80e707272d0d5055a532cdd80f9effffffff4871a5c1e79e90658fd40b3aa072eafde2105ce93452f2582897a8f9c9ba39d9000000006a473044022062cce23ea063d0bacb0976b8aeb13c705ddd053e1a2bf30770563e43f1e2f282022027bdaf97c4ff187524dfd6625506a8094e85b4a277efbe13a0f9af449eacb75001210245eff0f8025bc893847259c1f3d33b1d31e162752c2942586e366dc7e0cb4b7cffffffff71d166500b95800845331252a51e33402798688772d3a28794800dbeb0ce1cbd000000006b483045022100c54cbc79d810e78d6e4ce0da2bd3dc1a29c28d9a2728d9691999235504ad75c0022065b328fdb13e8704979c3a99939c737366c55aa499db2babfaa44bcd201fede6012102458419cfe98087a1b79933f7aa26060ddf79881ad1e0fedc379cad3ecfcabe11fffffffffde5e5b3b48461efa0ec2c4f5d6c170cc64c296f06bf1b0cf159481202dfe02b2a0000006b48304502210097dcaab476849bc04dc3c612cf51a1b302327d0f9c17338269e32bcb5eeb9179022054039b495ffff10814067b8b6667cbb981a99c9ae59989fd055b7f0533aa298e0121037c8086e09eccfd8f6fa40dec2966a60a97ee596c11e6e6674504b82c2a54d355ffffffff877848f1e62e22d930e25e462f5c26d84e84c38be17f47d201506b01117c9d2a000000006b483045022100821ca16b2bd4e127e0a5d803cc636e353137c23afbff7f99af5fb1d12a2cabb302202a25893262abedd5ab41a4ea358ab97e25144dfab1581b45e58aea939283151e0121028f818d4d902114d4b8b3a1b6a71758068b8d933f29ca67a2e520468f6a218888ffffffffd447347b43cae3426a1998d42c85eb18a35ee3d5c928326db7345bb98305636a310100006b483045022100969d35f8721c10ff7d8f1346dffc6210e8c8377af606980522d8d68eadf66b9502201e994dd4b2328f7722a5228e4ec002f221d016ccee4ad905e7ed4a4f9f3f56d6012102ea7e4daf42277aa0ca2be327c3618f7d1ff1fd6c530f4323792c79b1476890f2ffffffff1606d864bab5c97b25d5455681befb825e2d20ebf2940a0f098d39c6e4f36b9c050000006a47304402205169b07107cbce69068f9d5fe231cff8fdfe23078bb22ea4fb8bda0595838ff6022075d1e30e041b91a27d0406627045bb1084e24d3c095e98a23ade9e9d4579fe60012103cc7dfdd10a3dde00a3a217967a0d69e715d941a3456469c215fe80d7bab3f425ffffffff4db18094a111d61a3d8e9dd91f7d169334e9bee31f14256bedcbdfc3931a6bcf000000006a4730440220470cccec334e52f2ca0ab9d8c856fe8cbb292d02e39d2816e9b74bd84dc8a5dc02207141340dc8717d50962ccec94032c78bba568c080994a8ba167a98a75ce65383012102529de6faf23372a348882e139a326abd3312519098026b3408d3f5713c6366b5fffffffff720c1c072418bda3998b43fbb934c914dfa17e41f93e5c9c9dd1e19949688de000000006a47304402202fdb554fdfe93d90309c1f6597d68093e0345b705209173f0cbfae3414ac98110220720c0705816a44f77678405cdae96a039a266afefb181c029c599efd9fed10bd012102ab549199991425a269c27e26acebb9708754095ec2afb703a4977848e6d64748ffffffff9e4b3f75697024de5276860c1e930aca9838f86688bfa592d0414196848fecf6050000006a4730440220168ed5a3d93e07d11e961bc5bda63e262ac8f37a29df9c8b3e79b0fad3476d6d022051acc0f94419e8cf641eb8c98f0f513fec677c3b94d7f09da6e61d347e6f8c59012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff098ed13307000000001976a9143eee478f5adb348611c865ee9c62c9fbba0c81d788acc03dfb000000000017a914a72eae72b430fc05e7c3645977c62c94778a2abd8703e2d400000000001976a914e74eb2be3b5c450926f81a4e30482319c6c5923488ac0b2e9700000000001976a91442492e8b0154c7c51323dcea865ac2eb56a34ba888ac34427300000000001976a9145b42e90f591360c9e3e35aff70a88ed69845c01588aca63d3100000000001976a9145ee4488969a3daf4ee88b1022da129377a72ed6e88ac408e2c00000000001976a914d5a573e1498660664281bac4c32ede4c5c291e9788acbb5d2c00000000001976a914d664c0d62972bbe69ff8c9de3f1e28aa418ca02e88ac4b8b6c470d0000001976a914cebb2851a9c7cfe2582c12ecaf7f3ff4383d1dc088ac00000000",
Seq(
"15UjNGyUaVkcdBbJJt2qmTUnp31Q2y1e3K",
"1EKymUr8qh9LwmyqhA6qUwrUAK2MkyJXUN",
"1Kr6QSydW9bFQG1mXiPNNu6WpJGmUa9i1g",
"1JoBvMiprwzBgiWEh2MBJDDjfqpv9MGHAE",
"1BRqbLmLYJAia1Gmv6uwZGkafV3qEQzXC7",
"1Ctsa71j7NZXF7bSd38FSaCVTVjS5N2nw",
"15yoD6VvzWT1yB63mMuDNWweT1t5BtrBfb",
"1GgeJPMwo4Ky2ogB1yLQHQ1s6aC5sq8bY4",
"17B63j7rVk6VFL4GAKoWnwAXmSFZ8zS1rr",
"17JM5Ycf7BTokyTdo22bcCyxxj8DGgdFTz",
"1B676biYzr1cENKthsVLU2bD9FAn5ToHEb",
"13JjDQNrLBw2tHz2PJbKpMdvpdGzYthDnq",
"1LfoGGtjDLE4yBurvnwPKDyHFwD7emQDqq",
"1N3JVEPmmC4zSRdppFrHDQaXGqVCUWTWpE",
"12KDyoRUd7JLKYe1Ywn4XFeDnGw2vqb1sp",
"1Kr6QSydW9bFQG1mXiPNNu6WpJGmUa9i1g"
),
true /* valid for addresses */, true /* signatures match */
)
val randomBad1 = ( // v this char is different. Should be 3 instead of 2
"02000000109cfb5f661d567f3e94fcce58b1a9dccbaeeab6b60324247ded132db2326bd224010000006a47304402207cb1857edea9558ef8d15604d2f7dedfc292c3f7a50d2d31b5a223029bb76eca02205ce9cb5ceb2b2ad1b49312f89445e63f97df89466d54c1a4e07213a773abd21f012102cbe504d85e90ec24ddf218c65a54d28d69a21e46ba138749dc5fe9d055b481d0ffffffff49b793827f976c1e0dd569f4e314aa6d41eecaf3744b13eef479c508f9c720691f0000006b483045022100d1651d02ea21f95d7bf9b3e278c0e563155d3031aeb08c8d79f917393340156102203f0987ad5e5c7d82351a3bece6862687fe44f37567e1cfc21b2b5e92f251010f012102efdfea8121169abbf9a2382cf3dfa84f49578bf91260712cc3056751f8cd86b4ffffffffd77137df7c46595bcfe55413f2f6211065795ec47804b4dd2172f56ee7ee1fa1050000006a47304402201ac3524452a931be42f80caeeab4811f2de5c0fbd545a9e640fc1941a1f6d0d8022061bfcb5c37056d13721533a7c0523953dce8168b3a352cb1079d7aec8310f59d012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775290000006a47304402206f83790ebaa994641bd734f0383f2be8d4d22865a5115dbcf29c11bfda091f570220246a456c79348355a0136ba70c21ce7e0eb4cc5878a115b6029c4c8c12320bfe012102673197289d95ee7bb0d6b7da15a052da5895da014aeafc8d7e33d9267abaebc1ffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775270000006a47304402207b675760af32baf5c3eb6275852f258639dbb70df2f7d7c189a4cc404825ede30220484439f88bc18fc9b04f92906e6750c1b873de24d6eaf09d4f70cdf148dd77ab0121036b591a9dccf916597bb1029911f90243d9dde68f51ee49bab3bf65ac57e3d641ffffffffa5fe79d9b0cb63cbd4fef34e3dec849ba23af69830b1375d2361ef204326c77a000000006a47304402200f67cb96573a16899a320cada532d4bd980071ed82e6d272b9e79b258790376c022074458f7a82259790b454274f418156c1dd69cb730c4af64d6caa5abd140f361b01210200cbb2c571e8bd14c245ff56163e157d068a3545e8f26eed980964e766b377f8ffffffff313e1a72a479df16809dfe1e239526c896d54366a075b93b6d437d115bf4664e000000006a47304402203e5ec41a0a0b5cc43802fd941a177f3c2ed2f3cdf7d16f040d374785770dcc0002204f6da5bae3db0b3b3620154d5046e4d09f577f36afcd612b031a5332006ef1f201210254dcfe791eab7d5dcb581c0f969911432b8e80e707272d0d5055a532cdd80f9effffffff4871a5c1e79e90658fd40b3aa072eafde2105ce93452f2582897a8f9c9ba39d9000000006a473044022062cce23ea063d0bacb0976b8aeb13c705ddd053e1a2bf30770563e43f1e2f282022027bdaf97c4ff187524dfd6625506a8094e85b4a277efbe13a0f9af449eacb75001210245eff0f8025bc893847259c1f3d33b1d31e162752c2942586e366dc7e0cb4b7cffffffff71d166500b95800845331252a51e33402798688772d3a28794800dbeb0ce1cbd000000006b483045022100c54cbc79d810e78d6e4ce0da2bd3dc1a29c28d9a2728d9691999235504ad75c0022065b328fdb13e8704979c3a99939c737366c55aa499db2babfaa44bcd201fede6012102458419cfe98087a1b79933f7aa26060ddf79881ad1e0fedc379cad3ecfcabe11fffffffffde5e5b3b48461efa0ec2c4f5d6c170cc64c296f06bf1b0cf159481202dfe02b2a0000006b48304502210097dcaab476849bc04dc3c612cf51a1b302327d0f9c17338269e32bcb5eeb9179022054039b495ffff10814067b8b6667cbb981a99c9ae59989fd055b7f0533aa298e0121037c8086e09eccfd8f6fa40dec2966a60a97ee596c11e6e6674504b82c2a54d355ffffffff877848f1e62e22d930e25e462f5c26d84e84c38be17f47d201506b01117c9d2a000000006b483045022100821ca16b2bd4e127e0a5d803cc636e353137c23afbff7f99af5fb1d12a2cabb302202a25893262abedd5ab41a4ea358ab97e25144dfab1581b45e58aea939283151e0121028f818d4d902114d4b8b3a1b6a71758068b8d933f29ca67a2e520468f6a218888ffffffffd447347b43cae3426a1998d42c85eb18a35ee3d5c928326db7345bb98305636a310100006b483045022100969d35f8721c10ff7d8f1346dffc6210e8c8377af606980522d8d68eadf66b9502201e994dd4b2328f7722a5228e4ec002f221d016ccee4ad905e7ed4a4f9f3f56d6012102ea7e4daf42277aa0ca2be327c3618f7d1ff1fd6c530f4323792c79b1476890f2ffffffff1606d864bab5c97b25d5455681befb825e2d20ebf2940a0f098d39c6e4f36b9c050000006a47304402205169b07107cbce69068f9d5fe231cff8fdfe23078bb22ea4fb8bda0595838ff6022075d1e30e041b91a27d0406627045bb1084e24d3c095e98a23ade9e9d4579fe60012103cc7dfdd10a3dde00a3a217967a0d69e715d941a3456469c215fe80d7bab3f425ffffffff4db18094a111d61a3d8e9dd91f7d169334e9bee31f14256bedcbdfc3931a6bcf000000006a4730440220470cccec334e52f2ca0ab9d8c856fe8cbb292d02e39d2816e9b74bd84dc8a5dc02207141340dc8717d50962ccec94032c78bba568c080994a8ba167a98a75ce65383012102529de6faf23372a348882e139a326abd3312519098026b3408d3f5713c6366b5fffffffff720c1c072418bda3998b43fbb934c914dfa17e41f93e5c9c9dd1e19949688de000000006a47304402202fdb554fdfe93d90309c1f6597d68093e0345b705209173f0cbfae3414ac98110220720c0705816a44f77678405cdae96a039a266afefb181c029c599efd9fed10bd012102ab549199991425a269c27e26acebb9708754095ec2afb703a4977848e6d64748ffffffff9e4b3f75697024de5276860c1e930aca9838f86688bfa592d0414196848fecf6050000006a4730440220168ed5a3d93e07d11e961bc5bda63e262ac8f37a29df9c8b3e79b0fad3476d6d022051acc0f94419e8cf641eb8c98f0f513fec677c3b94d7f09da6e61d347e6f8c59012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff098ed13307000000001976a9143eee478f5adb348611c865ee9c62c9fbba0c81d788acc03dfb000000000017a914a72eae72b430fc05e7c3645977c62c94778a2abd8703e2d400000000001976a914e74eb2be3b5c450926f81a4e30482319c6c5923488ac0b2e9700000000001976a91442492e8b0154c7c51323dcea865ac2eb56a34ba888ac34427300000000001976a9145b42e90f591360c9e3e35aff70a88ed69845c01588aca63d3100000000001976a9145ee4488969a3daf4ee88b1022da129377a72ed6e88ac408e2c00000000001976a914d5a573e1498660664281bac4c32ede4c5c291e9788acbb5d2c00000000001976a914d664c0d62972bbe69ff8c9de3f1e28aa418ca02e88ac4b8b6c470d0000001976a914cebb2851a9c7cfe2582c12ecaf7f3ff4383d1dc088ac00000000",
Seq(
"15UjNGyUaVkcdBbJJt2qmTUnp31Q2y1e3K",
"1EKymUr8qh9LwmyqhA6qUwrUAK2MkyJXUN",
"1Kr6QSydW9bFQG1mXiPNNu6WpJGmUa9i1g",
"1JoBvMiprwzBgiWEh2MBJDDjfqpv9MGHAE",
"1BRqbLmLYJAia1Gmv6uwZGkafV3qEQzXC7",
"1Ctsa71j7NZXF7bSd38FSaCVTVjS5N2nw",
"15yoD6VvzWT1yB63mMuDNWweT1t5BtrBfb",
"1GgeJPMwo4Ky2ogB1yLQHQ1s6aC5sq8bY4",
"17B63j7rVk6VFL4GAKoWnwAXmSFZ8zS1rr",
"17JM5Ycf7BTokyTdo22bcCyxxj8DGgdFTz",
"1B676biYzr1cENKthsVLU2bD9FAn5ToHEb",
"13JjDQNrLBw2tHz2PJbKpMdvpdGzYthDnq",
"1LfoGGtjDLE4yBurvnwPKDyHFwD7emQDqq",
"1N3JVEPmmC4zSRdppFrHDQaXGqVCUWTWpE",
"12KDyoRUd7JLKYe1Ywn4XFeDnGw2vqb1sp",
"1Kr6QSydW9bFQG1mXiPNNu6WpJGmUa9i1g"
),
false /* not valid for addresses (because signatures don't match) */, false /* signatures don't match */
)
val randomBad2 = (
"02000000109cfb5f661d567f3e94fcce58b1a9dccbaeeab6b60324247ded133db2326bd224010000006a47304402207cb1857edea9558ef8d15604d2f7dedfc292c3f7a50d2d31b5a223029bb76eca02205ce9cb5ceb2b2ad1b49312f89445e63f97df89466d54c1a4e07213a773abd21f012102cbe504d85e90ec24ddf218c65a54d28d69a21e46ba138749dc5fe9d055b481d0ffffffff49b793827f976c1e0dd569f4e314aa6d41eecaf3744b13eef479c508f9c720691f0000006b483045022100d1651d02ea21f95d7bf9b3e278c0e563155d3031aeb08c8d79f917393340156102203f0987ad5e5c7d82351a3bece6862687fe44f37567e1cfc21b2b5e92f251010f012102efdfea8121169abbf9a2382cf3dfa84f49578bf91260712cc3056751f8cd86b4ffffffffd77137df7c46595bcfe55413f2f6211065795ec47804b4dd2172f56ee7ee1fa1050000006a47304402201ac3524452a931be42f80caeeab4811f2de5c0fbd545a9e640fc1941a1f6d0d8022061bfcb5c37056d13721533a7c0523953dce8168b3a352cb1079d7aec8310f59d012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775290000006a47304402206f83790ebaa994641bd734f0383f2be8d4d22865a5115dbcf29c11bfda091f570220246a456c79348355a0136ba70c21ce7e0eb4cc5878a115b6029c4c8c12320bfe012102673197289d95ee7bb0d6b7da15a052da5895da014aeafc8d7e33d9267abaebc1ffffffff1383b9c27a6acb87405382f312e52cd682d0d7377dc684f457b73de0aef1f775270000006a47304402207b675760af32baf5c3eb6275852f258639dbb70df2f7d7c189a4cc404825ede30220484439f88bc18fc9b04f92906e6750c1b873de24d6eaf09d4f70cdf148dd77ab0121036b591a9dccf916597bb1029911f90243d9dde68f51ee49bab3bf65ac57e3d641ffffffffa5fe79d9b0cb63cbd4fef34e3dec849ba23af69830b1375d2361ef204326c77a000000006a47304402200f67cb96573a16899a320cada532d4bd980071ed82e6d272b9e79b258790376c022074458f7a82259790b454274f418156c1dd69cb730c4af64d6caa5abd140f361b01210200cbb2c571e8bd14c245ff56163e157d068a3545e8f26eed980964e766b377f8ffffffff313e1a72a479df16809dfe1e239526c896d54366a075b93b6d437d115bf4664e000000006a47304402203e5ec41a0a0b5cc43802fd941a177f3c2ed2f3cdf7d16f040d374785770dcc0002204f6da5bae3db0b3b3620154d5046e4d09f577f36afcd612b031a5332006ef1f201210254dcfe791eab7d5dcb581c0f969911432b8e80e707272d0d5055a532cdd80f9effffffff4871a5c1e79e90658fd40b3aa072eafde2105ce93452f2582897a8f9c9ba39d9000000006a473044022062cce23ea063d0bacb0976b8aeb13c705ddd053e1a2bf30770563e43f1e2f282022027bdaf97c4ff187524dfd6625506a8094e85b4a277efbe13a0f9af449eacb75001210245eff0f8025bc893847259c1f3d33b1d31e162752c2942586e366dc7e0cb4b7cffffffff71d166500b95800845331252a51e33402798688772d3a28794800dbeb0ce1cbd000000006b483045022100c54cbc79d810e78d6e4ce0da2bd3dc1a29c28d9a2728d9691999235504ad75c0022065b328fdb13e8704979c3a99939c737366c55aa499db2babfaa44bcd201fede6012102458419cfe98087a1b79933f7aa26060ddf79881ad1e0fedc379cad3ecfcabe11fffffffffde5e5b3b48461efa0ec2c4f5d6c170cc64c296f06bf1b0cf159481202dfe02b2a0000006b48304502210097dcaab476849bc04dc3c612cf51a1b302327d0f9c17338269e32bcb5eeb9179022054039b495ffff10814067b8b6667cbb981a99c9ae59989fd055b7f0533aa298e0121037c8086e09eccfd8f6fa40dec2966a60a97ee596c11e6e6674504b82c2a54d355ffffffff877848f1e62e22d930e25e462f5c26d84e84c38be17f47d201506b01117c9d2a000000006b483045022100821ca16b2bd4e127e0a5d803cc636e353137c23afbff7f99af5fb1d12a2cabb302202a25893262abedd5ab41a4ea358ab97e25144dfab1581b45e58aea939283151e0121028f818d4d902114d4b8b3a1b6a71758068b8d933f29ca67a2e520468f6a218888ffffffffd447347b43cae3426a1998d42c85eb18a35ee3d5c928326db7345bb98305636a310100006b483045022100969d35f8721c10ff7d8f1346dffc6210e8c8377af606980522d8d68eadf66b9502201e994dd4b2328f7722a5228e4ec002f221d016ccee4ad905e7ed4a4f9f3f56d6012102ea7e4daf42277aa0ca2be327c3618f7d1ff1fd6c530f4323792c79b1476890f2ffffffff1606d864bab5c97b25d5455681befb825e2d20ebf2940a0f098d39c6e4f36b9c050000006a47304402205169b07107cbce69068f9d5fe231cff8fdfe23078bb22ea4fb8bda0595838ff6022075d1e30e041b91a27d0406627045bb1084e24d3c095e98a23ade9e9d4579fe60012103cc7dfdd10a3dde00a3a217967a0d69e715d941a3456469c215fe80d7bab3f425ffffffff4db18094a111d61a3d8e9dd91f7d169334e9bee31f14256bedcbdfc3931a6bcf000000006a4730440220470cccec334e52f2ca0ab9d8c856fe8cbb292d02e39d2816e9b74bd84dc8a5dc02207141340dc8717d50962ccec94032c78bba568c080994a8ba167a98a75ce65383012102529de6faf23372a348882e139a326abd3312519098026b3408d3f5713c6366b5fffffffff720c1c072418bda3998b43fbb934c914dfa17e41f93e5c9c9dd1e19949688de000000006a47304402202fdb554fdfe93d90309c1f6597d68093e0345b705209173f0cbfae3414ac98110220720c0705816a44f77678405cdae96a039a266afefb181c029c599efd9fed10bd012102ab549199991425a269c27e26acebb9708754095ec2afb703a4977848e6d64748ffffffff9e4b3f75697024de5276860c1e930aca9838f86688bfa592d0414196848fecf6050000006a4730440220168ed5a3d93e07d11e961bc5bda63e262ac8f37a29df9c8b3e79b0fad3476d6d022051acc0f94419e8cf641eb8c98f0f513fec677c3b94d7f09da6e61d347e6f8c59012103786af4b32017ec640dba2d2a7e1fd5aa4a231a658e4cbc114d51c031576e19bcffffffff098ed13307000000001976a9143eee478f5adb348611c865ee9c62c9fbba0c81d788acc03dfb000000000017a914a72eae72b430fc05e7c3645977c62c94778a2abd8703e2d400000000001976a914e74eb2be3b5c450926f81a4e30482319c6c5923488ac0b2e9700000000001976a91442492e8b0154c7c51323dcea865ac2eb56a34ba888ac34427300000000001976a9145b42e90f591360c9e3e35aff70a88ed69845c01588aca63d3100000000001976a9145ee4488969a3daf4ee88b1022da129377a72ed6e88ac408e2c00000000001976a914d5a573e1498660664281bac4c32ede4c5c291e9788acbb5d2c00000000001976a914d664c0d62972bbe69ff8c9de3f1e28aa418ca02e88ac4b8b6c470d0000001976a914cebb2851a9c7cfe2582c12ecaf7f3ff4383d1dc088ac00000000",
Seq(
"15UjNGyUaVkcdBbJJt2qmTUnp31Q2y1e3K",
"1EKymUr8qh9LwmyqhA6qUwrUAK2MkyJXUN",
"1Kr6QSydW9bFQG1mXiPNNu6WpJGmUa9i1g",
"1JoBvMiprwzBgiWEh2MBJDDjfqpv9MGHAE",
"1BRqbLmLYJAia1Gmv6uwZGkafV3qEQzXC7",
"1Ctsa71j7NZXF7bSd38FSaCVTVjS5N2nw",
"15yoD6VvzWT1yB63mMuDNWweT1t5BtrBfb",
"1GgeJPMwo4Ky2ogB1yLQHQ1s6aC5sq8bY4",
"17B63j7rVk6VFL4GAKoWnwAXmSFZ8zS1rr",
"17JM5Ycf7BTokyTdo22bcCyxxj8DGgdFTz",
"1B676biYzr1cENKthsVLU2bD9FAn5ToHEb",
"13JjDQNrLBw2tHz2PJbKpMdvpdGzYthDnq",
"1LfoGGtjDLE4yBurvnwPKDyHFwD7emQDqq",
"1N3JVEPmmC4zSRdppFrHDQaXGqVCUWTWpE",
"12KDyoRUd7JLKYe1Ywn4XFeDnGw2vqb1sp",
"14e5YtfVYn6xJMCj77dRW5ESJCGyExx4vs" // this address is wrong
),
false /* valid for addresses */, true /* signatures match */
)
val bad = (
"01000000012F4C73B482A37EC8150615BC87167493A4683C29CB7CC9293B325BCB1382E27F000000008A47304402202D6B958AD0B899E9EFC6D1E8515AE3BA54A45EA3C35D58D0879CEFAFDCAE2E4602205CFBACEC1F0634C17F72E1216EB763EB89D408333250EAB8E692004E0932762101410486D38B39148A22EFAE1B78B6FFDE0B5D63F26CDC0C00EA232B916AFB6AF04EEF08E9A0E92DE8BD6BF58B59A3C24373BBE7DE9B51BCCB3261A95735123E963BAEFFFFFFFF02F46DD1080000000017A914B9468E6E9E9B0F3CE974CFD358574C3D99FA4B0487D48C1903000000001976A91427EB90E24E9DFA208781E3ABDF91EA9A2FC970D788AC00000000",
Seq("14e5YtfVYn6xJMCj77dRW5ESJCGyExx4vs"),
false, true
)
val good = (
"01000000012f4c73b482a37ec8150615bc87167493a4683c29cb7cc9293b325bcb1382e27f000000008b483045022100ebd538a8e2dae09a832b6a86eb3568788940a7c3760a21f30ee4f5653a9fbf330220374eb39975c10390c9a3685b62d103fcf3dcba6b3df0e5ffd999344f9d9738490141046e807dd9b135f4947c650e58923a99d7b317ff9b63f7abab2fadcf794e937f711f7ebd2681492ce675c60cefeb0fb6af56fa3942d89c651e93a0fb30c5f82edbffffffff01b0feea0b000000001976a914302582908abcd3079534ff7cc75e94aa9d1f974288ac00000000",
Seq("14e5YtfVYn6xJMCj77dRW5ESJCGyExx4vs"),
true, true
)
isMainNet = true
Seq(bad, good, randomGood, randomBad1, randomBad2).map{
case (hex, inAddresses, isAddressValid, isSigned) =>
val tx = new TxParser(hex.decodeHex).getTx
val values = tx.ins.map(_ => BigInt(0))
assert(tx.isSigned(values, Some(inAddresses)) == isAddressValid, "Test 1 failed")
assert(tx.isSigned(values) == isSigned)
print(".")
//println("Test passed for txid: "+tx.txid)
}
println
println("Signature tests passed")
}
object TestSegWit {
// creates tx with mixed inputs (segwit, p2pkh and p2sh-p2pk) types as examples
isMainNet = false // set to testnet
val key = new ECCPrvKey("BB2AC60BC518C0E239D5AF9D8D051A6BDFD0D931268DCA70C59E5992", true) // random key
val p2wpkh_key = new PrvKey_P2SH_P2WPKH(key.bigInt, false) // mainnet is false
val p2sh_key = new PrvKey_P2SH_P2PK(key, false) // mainnet is false
val p2pkh_key = new PrvKey_P2PKH(key, false) // mainnet is false
assert(p2wpkh_key.pubKey.address == "2N6nA4btbY23GTQ4RJi3mMGTonzXN7dbphE") // (segwit)
assert(p2sh_key.pubKey.address == "2MwprvB9tUMtX4vK8zJK8K329fNu79CJgR7") // (p2sh)
assert(p2pkh_key.pubKey.address == "muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1") // (p2pkh)
// Send some coins to the above addresses. During testing, the following coins were used:
val in0 = TxIn("0224c8875a43c482c81a508fafc10bd0f084b27b5543c228e48431985f321547", 0) // p2pkh
val in1 = TxIn("63bec90405a0c173ae928860a1e1d403e507ec225e2cdd07717c8408820d418b", 0) // segwit // 2031250 satoshis
val in2 = TxIn("db5a23f0da2502b8ef82d93453aa3be0b6e9a3ecfbfbc00818dc32b3c712d2d0", 0) // p2pkh
val in3 = TxIn("6d73e3c8f66869859dc5c1ba73f252b8db51950ebc1fc4a59dca3552a0085f9a", 0) // p2sh
val in4 = TxIn("6ce466eb0920f84cc2cfde1d359176c0baab7dc442e4e5763bf67e8fa96ee6a4", 0) // p2sh
val in5 = TxIn("b49f3d6d15f2bdd9217ba3caaf1bb1f2d9875c9657e6b0ac7a0ef841d486ad1d", 2) // p2pkh
val in6 = TxIn("b75dfb27477834b3060c8e956273bef81c62689a8b9ebb7cd4a8119508c2c798", 0) // segwit // 1015625 satoshis
// the following output was used to test
// Note 2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF faucet address
val out1 = TxOut(Some("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"), 32206092) // total amount is slightly more than 32206092
//val tx0 = createSegWitTxRaw(Seq(in0,in1,in2,in3,in4,in5,in6), Seq(out1)) // unsigned tx
// should also work with the initial tx is nonsegwit
val tx0 = createTxRaw(Seq(in0,in1,in2,in3,in4,in5,in6), Seq(out1)) // unsigned tx
val tx1 = p2pkh_key.signTx_P2PKH (tx0, Seq(0, 2, 5)) // inputs 0, 2, 5 are P2PKH
val tx2 = p2wpkh_key.signTx(
tx1, Seq(
(1, 2031250),
(6, 1015625)
)
) // inputs 1, 6 are segwit. Those need the input value in satoshis as well
val signed = p2sh_key.signTx_P2SH_P2PK(tx2, Seq(3, 4)) // inputs 3, 4 are P2SH_P2PK
val parsed = new TxParser(signed).getTx
val values = Seq(0, 2031250, 0, 0, 0, 0, 1015625).map(BigInt(_))
assert(parsed.isSigned(values))
val origHex = "010000000001074715325F983184E428C243557BB284F0D00BC1AF8F501AC882C4435A87C82402000000006A47304402206F2EB176FC6E278B67301628DD16F1F9A5C751E05F8011B65787CB8061C2283002203A701DBC419F2DF11F54AAF59E627318C4DFC8A5873CB1AEF7FBD882543E362F0121039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235FFFFFFFF8B410D8208847C7107DD2C5E22EC07E503D4E1A1608892AE73C1A00504C9BE63000000001716001497ACCE1F07FC7D118F4A0CEA16B72D567F151CB6FFFFFFFFD0D212C7B332DC1808C0FBFBECA3E9B6E03BAA5334D982EFB80225DAF0235ADB000000006B483045022100D97C3EAE660C763C15806C9A0B8B26C87C23378BA4F3A6DEF4C343EFF1F4B5E0022068BAB5B297EB8ACF054A4FCCD99ADD823D5EC27A1F21339CCF60BA460ACFE53E0121039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235FFFFFFFF9A5F08A05235CA9DA5C41FBC0E9551DBB852F273BAC1C59D856968F6C8E3736D000000006D48304502210083161E876C64B1351D49738435C1415FFC963B6B0D0736DE560C691C2CDDF779022016CE4081B19E2D26E5F58B8B8EC343033A78A31EBD83702E323274F23ACF2E1A012321039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235ACFFFFFFFFA4E66EA98F7EF63B76E5E442C47DABBAC07691351DDECFC24CF82009EB66E46C000000006C473044022059F985A704B99EAABBF295767B4154593323B1DA504952DA8B6580A934D2121602206885D8FD5B1AA397FF8C3821944B5C7B87F7A13BE4248F31F6A3A12C8112202F012321039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235ACFFFFFFFF1DAD86D441F80E7AACB0E657965C87D9F2B11BAFCAA37B21D9BDF2156D3D9FB4020000006A47304402207337C6B88C4BC9AA586F7807881BE07AECA37369975832FB6F45993BC1FA6BC902203ECA9744C6DD9B2FE6D0DB3A347CDD04A93FE84CCD279881D60178C041B352670121039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235FFFFFFFF98C7C2089511A8D47CBB9E8B9A68621CF8BE7362958E0C06B334784727FB5DB7000000001716001497ACCE1F07FC7D118F4A0CEA16B72D567F151CB6FFFFFFFF010C6DEB010000000017A914A9974100AEEE974A20CDA9A2F545704A0AB54FDC8700024830450221009F68725D0143B7DBE85FE88930381693ACC66C83380A89F25BEB798F558C175F02205A8C9A15AE1DE018A0CB59DFC69FF6A690475431A28B5A26DAC052D47FA7999B0121039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE62350000000002483045022100D732A664CBC4C222EAAEAF6BB40E7B2DE50A426E85D2A4C712C4DFAC6FC9501802201D8607360FBB9E6DEF76E69D07F68FC9155CA4B54CC2335D42710145F8AA8DF40121039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE623500000000"
val origTxid = "3e1efea9ebc892d3c1d5fbc35fba973b42c819ce85fce74a435a2729674d4f0e"
val origHash = "596e904f07f3c5deaafdfa0d078c103e50957a804426e0c229775eb4085afeb1"
assert(origHex.toLowerCase == signed.encodeHex, "Hex signed tx mismatch")
assert(origTxid == parsed.txid, s"Txid mismatch. Computed ${parsed.txid}. Expected ${origTxid}")
assert(origHash == parsed.segWitTxHash, s"Hash mismatch. Computed ${parsed.segWitTxHash}. Expected ${origHash}")
/* Above tx was sent with txID c2e205d632d589b0a8c52fb71d7ecf35e112b241dca4a8e6d6b411764a630a28
https://www.blocktrail.com/tBTC/tx/c2e205d632d589b0a8c52fb71d7ecf35e112b241dca4a8e6d6b411764a630a28
However during the initial test, we did not use deterministic k values of signature. So the id now will be different!
Current is as follows:
txid: 3e1efea9ebc892d3c1d5fbc35fba973b42c819ce85fce74a435a2729674d4f0e
hash: 596e904f07f3c5deaafdfa0d078c103e50957a804426e0c229775eb4085afeb1 */
println("P2SH_P2WPKH input tests passed")
}
object TestP2PKH {
// standard tx (most common till now). Sent to 1abc address (mainet) or mabc.. /nabc.. address (testnet)
val mainNet = false // set to testnet
isMainNet = mainNet
val compr = true
val key = new ECCPrvKey("BB2AC60BC518C0E239D5AF9D8D051A6BDFD0D931268DCA70C59E5992", compr)
val p2pkhKey = new PrvKey_P2PKH(key, mainNet)
assert(p2pkhKey.pubKey.address == "muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1")
// following inputs were used in creating tx (funds were sent to above muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1)
val in1 = TxIn("56585700f02e26d8d1f71634edbdab74b4eba06abbf55bb918352ed7d4942e0d", 0)
val in2 = TxIn("5ef0bea6abe1203f8521f61e2040024c39f48f7253df9ee3b919a8513bb01c36", 0)
// the following output was used to test
// Note 2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF faucet address
val out1 = TxOut(Some("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"), 48700000)
val tx = createTxRaw(Seq(in1, in2), Seq(out1))
val signed = p2pkhKey.signTx_P2PKH(tx, Seq(0, 1)) // inputs 0 and 1 are P2PKH inputs
val parsed = new TxParser(signed).getTx
// println("Hex: "+signed.encodeHex)
assert(parsed.txid == "2e18fad68f103cc013dc7eb46001dbbf3bdc9768273f58a2a80ed51c7cee3b36")
assert(parsed.txid == parsed.segWitTxHash)
assert(parsed.isSigned(Seq(0, 0)))
println("P2PKH input tests passed")
}
object TestP2PKHPushTx extends App {
// standard tx (most common till now). Sent to 1abc address (mainet) or mabc.. /nabc.. address (testnet)
val mainNet = false // set to testnet
isMainNet = mainNet
val compr = true
val key = new ECCPrvKey("BB2AC60BC518C0E239D5AF9D8D051A6BDFD0D931268DCA70C59E5992", compr)
val p2pkhKey = new PrvKey_P2PKH(key, mainNet)
assert(p2pkhKey.pubKey.address == "muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1")
// following inputs were used in creating tx (funds were sent to above muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1)
val in1 = TxIn("9652b16e1d4956ad187d8462eb718c0cb09b7482badb97e1fdd4d9869c5bee38", 0)
// the following output was used to test
// Note 2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF faucet address
val out1 = TxOut(Some("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"), 129000000)
val tx = createTxRaw(Seq(in1), Seq(out1))
val signed = p2pkhKey.signTx_P2PKH(tx, Seq(0)) // input 0 is P2PKH inputs
val parsed = new TxParser(signed).getTx
println("Hex: "+signed.encodeHex)
}
object TestP2SH_P2PK {
// uses P2SH_P2PK described in https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
val mainNet = false // set to testnet
isMainNet = mainNet
val compr = true
val key = new ECCPrvKey("BB2AC60BC518C0E239D5AF9D8D051A6BDFD0D931268DCA70C59E5992", compr)
val p2shKey = new PrvKey_P2SH_P2PK(key, mainNet)
val p2pkhKey = new PrvKey_P2PKH(key, mainNet)
assert(p2shKey.pubKey.address == "2MwprvB9tUMtX4vK8zJK8K329fNu79CJgR7")
assert(p2pkhKey.pubKey.address == "muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1")
// following inputs were used to create tx
val in2 = TxIn("d9524c287a4f6d6f072244faab539f1ed8541b557bd904a3f56f51f371786a0f", 0) // 0.34000000 // 2MwprvB9tUMtX4vK8zJK8K329fNu79CJgR7
val in3 = TxIn("a1ba359c11255e366e1a0adf6a3d8fd148960468114913779c1420919d382591", 0) // 1.3 // muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1
val in4 = TxIn("5e5628b2f631955a425deae64da883d36b003ce75e668b7e5b12988e6dca55f4", 0) // 0.08125000 // muLwLjVipwixXcECVMcEwgsrtfGRTB4zB1
// the following output was used to test
// Note 2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF faucet address
val out2 = TxOut(Some("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"), 172000000)
val tx = createTxRaw(Seq(in2, in3, in4), Seq(out2))
val tx1 = p2shKey.signTx_P2SH_P2PK(tx, Seq(0))
val tx2 = p2pkhKey.signTx_P2PKH(tx1, Seq(1, 2))
val signed = tx2.encodeHex
val parsed = new TxParser(tx2).getTx
assert(parsed.outs(0).optAddress.get == "2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF")
assert(parsed.txid == "491cd5eb0439cf751bb24e81ab8baa9407e7d83819f843581c31c9c9f5c7e3d1")
assert(parsed.isSigned(Seq(0, 0, 0)))
println("P2SH_P2PK input tests passed")
}
object TestMixedOutputs {
Seq(true, false).map{mainNet =>
isMainNet = mainNet
1 to 10 foreach{i =>
val outs = 1 to 10 map {j =>
val h = sha256Bytes2Bytes((i+":"+j).getBytes)
val int = BigInt(sha256Bytes2Bytes(h))
val isCompressed = h(0).isEven
val eccKey = new ECCPrvKey(int mod n, isCompressed)
val which = (BigInt(h(1)) mod 3).toInt
val key = which match {
case 0 => new PrvKey_P2PKH(eccKey, isMainNet)
case 1 => new PrvKey_P2SH_P2PK(eccKey, isMainNet)
case 2 => new PrvKey_P2SH_P2WPKH(int mod n, isMainNet)
}
val addr = key.pubKey.address
new TxOut(addr, i * j+30000)
}
val ins = 1 to 10 map {j =>
val hash = sha256Bytes2Bytes((i+":"+j+":"+1).getBytes).encodeHex.toLowerCase
val vOut = j
TxIn(hash, vOut)
}
val raw = createTxRaw(ins, outs)
val tx = new TxParser(raw).getTx
//println("Hex: "+tx.serialize.encodeHex)
tx.outs zip outs foreach{
case (o1, o2) =>
assert(o1.optAddress.get == o2.optAddress.get)
assert(o1.optScriptPubKey.get == o2.optScriptPubKey.get)
}
print(".")
}
}
println
println("Mixed input tests passed")
}