@btc-vision/bitcoin 6.5.6 → 7.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/HOW_TO_WRITE_GOOD_CODE.md +2436 -0
  2. package/benchmark/psbt-2000-inputs.bench.ts +178 -0
  3. package/benchmark/signing.bench.ts +147 -0
  4. package/browser/address.d.ts +56 -9
  5. package/browser/address.d.ts.map +1 -0
  6. package/browser/bech32utils.d.ts +9 -1
  7. package/browser/bech32utils.d.ts.map +1 -0
  8. package/browser/bip66.d.ts +11 -6
  9. package/browser/bip66.d.ts.map +1 -0
  10. package/browser/block.d.ts +117 -11
  11. package/browser/block.d.ts.map +1 -0
  12. package/browser/branded.d.ts +20 -0
  13. package/browser/branded.d.ts.map +1 -0
  14. package/browser/crypto/crypto.d.ts +1 -0
  15. package/browser/crypto/crypto.d.ts.map +1 -0
  16. package/browser/crypto.d.ts +46 -7
  17. package/browser/crypto.d.ts.map +1 -0
  18. package/browser/ecc/context.d.ts +129 -0
  19. package/browser/ecc/context.d.ts.map +1 -0
  20. package/browser/ecc/index.d.ts +11 -0
  21. package/browser/ecc/index.d.ts.map +1 -0
  22. package/browser/ecc/types.d.ts +128 -0
  23. package/browser/ecc/types.d.ts.map +1 -0
  24. package/browser/ecpair.d.ts +99 -0
  25. package/browser/errors.d.ts +124 -0
  26. package/browser/errors.d.ts.map +1 -0
  27. package/browser/index.d.ts +32 -5
  28. package/browser/index.d.ts.map +1 -0
  29. package/browser/index.js +12482 -101
  30. package/browser/io/BinaryReader.d.ts +276 -0
  31. package/browser/io/BinaryReader.d.ts.map +1 -0
  32. package/browser/io/BinaryWriter.d.ts +391 -0
  33. package/browser/io/BinaryWriter.d.ts.map +1 -0
  34. package/browser/io/MemoryPool.d.ts +220 -0
  35. package/browser/io/MemoryPool.d.ts.map +1 -0
  36. package/browser/io/base64.d.ts +13 -0
  37. package/browser/io/base64.d.ts.map +1 -0
  38. package/browser/io/hex.d.ts +67 -0
  39. package/browser/io/hex.d.ts.map +1 -0
  40. package/browser/io/index.d.ts +17 -0
  41. package/browser/io/index.d.ts.map +1 -0
  42. package/browser/io/utils.d.ts +199 -0
  43. package/browser/io/utils.d.ts.map +1 -0
  44. package/browser/merkle.d.ts +10 -1
  45. package/browser/merkle.d.ts.map +1 -0
  46. package/browser/networks.d.ts +70 -9
  47. package/browser/networks.d.ts.map +1 -0
  48. package/browser/opcodes.d.ts +1 -0
  49. package/browser/opcodes.d.ts.map +1 -0
  50. package/browser/payments/bip341.d.ts +35 -9
  51. package/browser/payments/bip341.d.ts.map +1 -0
  52. package/browser/payments/embed.d.ts +112 -1
  53. package/browser/payments/embed.d.ts.map +1 -0
  54. package/browser/payments/index.d.ts +17 -10
  55. package/browser/payments/index.d.ts.map +1 -0
  56. package/browser/payments/p2ms.d.ts +150 -0
  57. package/browser/payments/p2ms.d.ts.map +1 -0
  58. package/browser/payments/p2op.d.ts +150 -24
  59. package/browser/payments/p2op.d.ts.map +1 -0
  60. package/browser/payments/p2pk.d.ts +154 -1
  61. package/browser/payments/p2pk.d.ts.map +1 -0
  62. package/browser/payments/p2pkh.d.ts +176 -1
  63. package/browser/payments/p2pkh.d.ts.map +1 -0
  64. package/browser/payments/p2sh.d.ts +150 -1
  65. package/browser/payments/p2sh.d.ts.map +1 -0
  66. package/browser/payments/p2tr.d.ts +185 -1
  67. package/browser/payments/p2tr.d.ts.map +1 -0
  68. package/browser/payments/p2wpkh.d.ts +161 -1
  69. package/browser/payments/p2wpkh.d.ts.map +1 -0
  70. package/browser/payments/p2wsh.d.ts +146 -1
  71. package/browser/payments/p2wsh.d.ts.map +1 -0
  72. package/browser/payments/types.d.ts +94 -64
  73. package/browser/payments/types.d.ts.map +1 -0
  74. package/browser/psbt/bip371.d.ts +34 -8
  75. package/browser/psbt/bip371.d.ts.map +1 -0
  76. package/browser/psbt/psbtutils.d.ts +56 -16
  77. package/browser/psbt/psbtutils.d.ts.map +1 -0
  78. package/browser/psbt/types.d.ts +245 -0
  79. package/browser/psbt/types.d.ts.map +1 -0
  80. package/browser/psbt/utils.d.ts +64 -0
  81. package/browser/psbt/utils.d.ts.map +1 -0
  82. package/browser/psbt/validation.d.ts +84 -0
  83. package/browser/psbt/validation.d.ts.map +1 -0
  84. package/browser/psbt.d.ts +82 -118
  85. package/browser/psbt.d.ts.map +1 -0
  86. package/browser/pubkey.d.ts +27 -6
  87. package/browser/pubkey.d.ts.map +1 -0
  88. package/browser/push_data.d.ts +24 -2
  89. package/browser/push_data.d.ts.map +1 -0
  90. package/browser/script.d.ts +33 -8
  91. package/browser/script.d.ts.map +1 -0
  92. package/browser/script_number.d.ts +17 -0
  93. package/browser/script_number.d.ts.map +1 -0
  94. package/browser/script_signature.d.ts +23 -5
  95. package/browser/script_signature.d.ts.map +1 -0
  96. package/browser/transaction.d.ts +160 -18
  97. package/browser/transaction.d.ts.map +1 -0
  98. package/browser/types.d.ts +36 -38
  99. package/browser/types.d.ts.map +1 -0
  100. package/browser/workers/WorkerSigningPool.d.ts +143 -0
  101. package/browser/workers/WorkerSigningPool.d.ts.map +1 -0
  102. package/browser/workers/WorkerSigningPool.node.d.ts +116 -0
  103. package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -0
  104. package/browser/workers/ecc-bundle.d.ts +25 -0
  105. package/browser/workers/ecc-bundle.d.ts.map +1 -0
  106. package/browser/workers/index.d.ts +91 -0
  107. package/browser/workers/index.d.ts.map +1 -0
  108. package/browser/workers/psbt-parallel.d.ts +88 -0
  109. package/browser/workers/psbt-parallel.d.ts.map +1 -0
  110. package/browser/workers/signing-worker.d.ts +37 -0
  111. package/browser/workers/signing-worker.d.ts.map +1 -0
  112. package/browser/workers/types.d.ts +365 -0
  113. package/browser/workers/types.d.ts.map +1 -0
  114. package/build/address.d.ts +57 -10
  115. package/build/address.d.ts.map +1 -0
  116. package/build/address.js +80 -24
  117. package/build/address.js.map +1 -0
  118. package/build/bech32utils.d.ts +9 -1
  119. package/build/bech32utils.d.ts.map +1 -0
  120. package/build/bech32utils.js +10 -2
  121. package/build/bech32utils.js.map +1 -0
  122. package/build/bip66.d.ts +11 -6
  123. package/build/bip66.d.ts.map +1 -0
  124. package/build/bip66.js +32 -3
  125. package/build/bip66.js.map +1 -0
  126. package/build/block.d.ts +117 -11
  127. package/build/block.d.ts.map +1 -0
  128. package/build/block.js +204 -72
  129. package/build/block.js.map +1 -0
  130. package/build/branded.d.ts +20 -0
  131. package/build/branded.d.ts.map +1 -0
  132. package/build/branded.js +7 -0
  133. package/build/branded.js.map +1 -0
  134. package/build/crypto/crypto.d.ts +1 -0
  135. package/build/crypto/crypto.d.ts.map +1 -0
  136. package/build/crypto/crypto.js +1 -0
  137. package/build/crypto/crypto.js.map +1 -0
  138. package/build/crypto.d.ts +46 -7
  139. package/build/crypto.d.ts.map +1 -0
  140. package/build/crypto.js +65 -20
  141. package/build/crypto.js.map +1 -0
  142. package/build/ecc/context.d.ts +135 -0
  143. package/build/ecc/context.d.ts.map +1 -0
  144. package/build/ecc/context.js +232 -0
  145. package/build/ecc/context.js.map +1 -0
  146. package/build/ecc/index.d.ts +11 -0
  147. package/build/ecc/index.d.ts.map +1 -0
  148. package/build/ecc/index.js +11 -0
  149. package/build/ecc/index.js.map +1 -0
  150. package/build/ecc/types.d.ts +134 -0
  151. package/build/ecc/types.d.ts.map +1 -0
  152. package/build/ecc/types.js +8 -0
  153. package/build/ecc/types.js.map +1 -0
  154. package/build/errors.d.ts +124 -0
  155. package/build/errors.d.ts.map +1 -0
  156. package/build/errors.js +155 -0
  157. package/build/errors.js.map +1 -0
  158. package/build/index.d.ts +32 -5
  159. package/build/index.d.ts.map +1 -0
  160. package/build/index.js +26 -3
  161. package/build/index.js.map +1 -0
  162. package/build/io/BinaryReader.d.ts +276 -0
  163. package/build/io/BinaryReader.d.ts.map +1 -0
  164. package/build/io/BinaryReader.js +425 -0
  165. package/build/io/BinaryReader.js.map +1 -0
  166. package/build/io/BinaryWriter.d.ts +391 -0
  167. package/build/io/BinaryWriter.d.ts.map +1 -0
  168. package/build/io/BinaryWriter.js +611 -0
  169. package/build/io/BinaryWriter.js.map +1 -0
  170. package/build/io/MemoryPool.d.ts +220 -0
  171. package/build/io/MemoryPool.d.ts.map +1 -0
  172. package/build/io/MemoryPool.js +309 -0
  173. package/build/io/MemoryPool.js.map +1 -0
  174. package/build/io/base64.d.ts +13 -0
  175. package/build/io/base64.d.ts.map +1 -0
  176. package/build/io/base64.js +20 -0
  177. package/build/io/base64.js.map +1 -0
  178. package/build/io/hex.d.ts +67 -0
  179. package/build/io/hex.d.ts.map +1 -0
  180. package/build/io/hex.js +138 -0
  181. package/build/io/hex.js.map +1 -0
  182. package/build/io/index.d.ts +17 -0
  183. package/build/io/index.d.ts.map +1 -0
  184. package/build/io/index.js +23 -0
  185. package/build/io/index.js.map +1 -0
  186. package/build/io/utils.d.ts +199 -0
  187. package/build/io/utils.d.ts.map +1 -0
  188. package/build/io/utils.js +271 -0
  189. package/build/io/utils.js.map +1 -0
  190. package/build/merkle.d.ts +10 -1
  191. package/build/merkle.d.ts.map +1 -0
  192. package/build/merkle.js +12 -1
  193. package/build/merkle.js.map +1 -0
  194. package/build/networks.d.ts +70 -9
  195. package/build/networks.d.ts.map +1 -0
  196. package/build/networks.js +90 -4
  197. package/build/networks.js.map +1 -0
  198. package/build/opcodes.d.ts +1 -0
  199. package/build/opcodes.d.ts.map +1 -0
  200. package/build/opcodes.js +1 -0
  201. package/build/opcodes.js.map +1 -0
  202. package/build/payments/bip341.d.ts +36 -9
  203. package/build/payments/bip341.d.ts.map +1 -0
  204. package/build/payments/bip341.js +35 -15
  205. package/build/payments/bip341.js.map +1 -0
  206. package/build/payments/embed.d.ts +120 -1
  207. package/build/payments/embed.d.ts.map +1 -0
  208. package/build/payments/embed.js +215 -34
  209. package/build/payments/embed.js.map +1 -0
  210. package/build/payments/index.d.ts +17 -10
  211. package/build/payments/index.d.ts.map +1 -0
  212. package/build/payments/index.js +20 -10
  213. package/build/payments/index.js.map +1 -0
  214. package/build/payments/p2ms.d.ts +159 -1
  215. package/build/payments/p2ms.d.ts.map +1 -0
  216. package/build/payments/p2ms.js +427 -108
  217. package/build/payments/p2ms.js.map +1 -0
  218. package/build/payments/p2op.d.ts +158 -24
  219. package/build/payments/p2op.d.ts.map +1 -0
  220. package/build/payments/p2op.js +379 -93
  221. package/build/payments/p2op.js.map +1 -0
  222. package/build/payments/p2pk.d.ts +162 -1
  223. package/build/payments/p2pk.d.ts.map +1 -0
  224. package/build/payments/p2pk.js +327 -58
  225. package/build/payments/p2pk.js.map +1 -0
  226. package/build/payments/p2pkh.d.ts +185 -1
  227. package/build/payments/p2pkh.d.ts.map +1 -0
  228. package/build/payments/p2pkh.js +467 -114
  229. package/build/payments/p2pkh.js.map +1 -0
  230. package/build/payments/p2sh.d.ts +159 -1
  231. package/build/payments/p2sh.d.ts.map +1 -0
  232. package/build/payments/p2sh.js +500 -152
  233. package/build/payments/p2sh.js.map +1 -0
  234. package/build/payments/p2tr.d.ts +193 -1
  235. package/build/payments/p2tr.d.ts.map +1 -0
  236. package/build/payments/p2tr.js +592 -174
  237. package/build/payments/p2tr.js.map +1 -0
  238. package/build/payments/p2wpkh.d.ts +170 -1
  239. package/build/payments/p2wpkh.d.ts.map +1 -0
  240. package/build/payments/p2wpkh.js +429 -104
  241. package/build/payments/p2wpkh.js.map +1 -0
  242. package/build/payments/p2wsh.d.ts +155 -1
  243. package/build/payments/p2wsh.d.ts.map +1 -0
  244. package/build/payments/p2wsh.js +466 -144
  245. package/build/payments/p2wsh.js.map +1 -0
  246. package/build/payments/types.d.ts +98 -64
  247. package/build/payments/types.d.ts.map +1 -0
  248. package/build/payments/types.js +17 -13
  249. package/build/payments/types.js.map +1 -0
  250. package/build/psbt/bip371.d.ts +35 -9
  251. package/build/psbt/bip371.d.ts.map +1 -0
  252. package/build/psbt/bip371.js +113 -28
  253. package/build/psbt/bip371.js.map +1 -0
  254. package/build/psbt/psbtutils.d.ts +56 -16
  255. package/build/psbt/psbtutils.d.ts.map +1 -0
  256. package/build/psbt/psbtutils.js +71 -16
  257. package/build/psbt/psbtutils.js.map +1 -0
  258. package/build/psbt/types.d.ts +249 -0
  259. package/build/psbt/types.d.ts.map +1 -0
  260. package/build/psbt/types.js +6 -0
  261. package/build/psbt/types.js.map +1 -0
  262. package/build/psbt/utils.d.ts +68 -0
  263. package/build/psbt/utils.d.ts.map +1 -0
  264. package/build/psbt/utils.js +171 -0
  265. package/build/psbt/utils.js.map +1 -0
  266. package/build/psbt/validation.d.ts +88 -0
  267. package/build/psbt/validation.d.ts.map +1 -0
  268. package/build/psbt/validation.js +149 -0
  269. package/build/psbt/validation.js.map +1 -0
  270. package/build/psbt.d.ts +84 -120
  271. package/build/psbt.d.ts.map +1 -0
  272. package/build/psbt.js +411 -412
  273. package/build/psbt.js.map +1 -0
  274. package/build/pubkey.d.ts +27 -6
  275. package/build/pubkey.d.ts.map +1 -0
  276. package/build/pubkey.js +36 -12
  277. package/build/pubkey.js.map +1 -0
  278. package/build/push_data.d.ts +24 -2
  279. package/build/push_data.d.ts.map +1 -0
  280. package/build/push_data.js +44 -12
  281. package/build/push_data.js.map +1 -0
  282. package/build/script.d.ts +33 -8
  283. package/build/script.d.ts.map +1 -0
  284. package/build/script.js +100 -36
  285. package/build/script.js.map +1 -0
  286. package/build/script_number.d.ts +17 -0
  287. package/build/script_number.d.ts.map +1 -0
  288. package/build/script_number.js +19 -0
  289. package/build/script_number.js.map +1 -0
  290. package/build/script_signature.d.ts +23 -5
  291. package/build/script_signature.d.ts.map +1 -0
  292. package/build/script_signature.js +48 -15
  293. package/build/script_signature.js.map +1 -0
  294. package/build/transaction.d.ts +160 -18
  295. package/build/transaction.d.ts.map +1 -0
  296. package/build/transaction.js +443 -176
  297. package/build/transaction.js.map +1 -0
  298. package/build/tsconfig.build.tsbuildinfo +1 -0
  299. package/build/types.d.ts +36 -38
  300. package/build/types.d.ts.map +1 -0
  301. package/build/types.js +175 -57
  302. package/build/types.js.map +1 -0
  303. package/build/workers/WorkerSigningPool.d.ts +174 -0
  304. package/build/workers/WorkerSigningPool.d.ts.map +1 -0
  305. package/build/workers/WorkerSigningPool.js +553 -0
  306. package/build/workers/WorkerSigningPool.js.map +1 -0
  307. package/build/workers/WorkerSigningPool.node.d.ts +124 -0
  308. package/build/workers/WorkerSigningPool.node.d.ts.map +1 -0
  309. package/build/workers/WorkerSigningPool.node.js +753 -0
  310. package/build/workers/WorkerSigningPool.node.js.map +1 -0
  311. package/build/workers/ecc-bundle.d.ts +25 -0
  312. package/build/workers/ecc-bundle.d.ts.map +1 -0
  313. package/build/workers/ecc-bundle.js +25 -0
  314. package/build/workers/ecc-bundle.js.map +1 -0
  315. package/build/workers/index.d.ts +91 -0
  316. package/build/workers/index.d.ts.map +1 -0
  317. package/build/workers/index.js +114 -0
  318. package/build/workers/index.js.map +1 -0
  319. package/build/workers/psbt-parallel.d.ts +117 -0
  320. package/build/workers/psbt-parallel.d.ts.map +1 -0
  321. package/build/workers/psbt-parallel.js +233 -0
  322. package/build/workers/psbt-parallel.js.map +1 -0
  323. package/build/workers/signing-worker.d.ts +37 -0
  324. package/build/workers/signing-worker.d.ts.map +1 -0
  325. package/build/workers/signing-worker.js +350 -0
  326. package/build/workers/signing-worker.js.map +1 -0
  327. package/build/workers/types.d.ts +365 -0
  328. package/build/workers/types.d.ts.map +1 -0
  329. package/build/workers/types.js +60 -0
  330. package/build/workers/types.js.map +1 -0
  331. package/package.json +66 -8
  332. package/scripts/bundle-ecc.ts +111 -0
  333. package/src/address.ts +81 -44
  334. package/src/bech32utils.ts +3 -3
  335. package/src/bip66.ts +34 -24
  336. package/src/block.ts +196 -84
  337. package/src/branded.ts +18 -0
  338. package/src/crypto.ts +64 -26
  339. package/src/ecc/context.ts +277 -0
  340. package/src/ecc/index.ts +14 -0
  341. package/src/ecc/types.ts +154 -0
  342. package/src/ecpair.d.ts +99 -0
  343. package/src/errors.ts +163 -0
  344. package/src/index.ts +113 -9
  345. package/src/io/BinaryReader.ts +461 -0
  346. package/src/io/BinaryWriter.ts +696 -0
  347. package/src/io/MemoryPool.ts +343 -0
  348. package/src/io/base64.ts +20 -0
  349. package/src/io/hex.ts +155 -0
  350. package/src/io/index.ts +41 -0
  351. package/src/io/utils.ts +283 -0
  352. package/src/merkle.ts +14 -9
  353. package/src/networks.ts +9 -9
  354. package/src/payments/bip341.ts +34 -33
  355. package/src/payments/embed.ts +244 -41
  356. package/src/payments/index.ts +12 -10
  357. package/src/payments/p2ms.ts +490 -118
  358. package/src/payments/p2op.ts +431 -133
  359. package/src/payments/p2pk.ts +370 -72
  360. package/src/payments/p2pkh.ts +524 -130
  361. package/src/payments/p2sh.ts +572 -172
  362. package/src/payments/p2tr.ts +686 -194
  363. package/src/payments/p2wpkh.ts +484 -107
  364. package/src/payments/p2wsh.ts +526 -164
  365. package/src/payments/types.ts +80 -66
  366. package/src/psbt/bip371.ts +68 -51
  367. package/src/psbt/psbtutils.ts +39 -40
  368. package/src/psbt/types.ts +331 -0
  369. package/src/psbt/utils.ts +188 -0
  370. package/src/psbt/validation.ts +192 -0
  371. package/src/psbt.ts +566 -809
  372. package/src/pubkey.ts +22 -23
  373. package/src/push_data.ts +18 -16
  374. package/src/script.ts +82 -64
  375. package/src/script_number.ts +6 -6
  376. package/src/script_signature.ts +33 -36
  377. package/src/transaction.ts +458 -238
  378. package/src/types.ts +231 -100
  379. package/src/workers/WorkerSigningPool.node.ts +887 -0
  380. package/src/workers/WorkerSigningPool.ts +670 -0
  381. package/src/workers/ecc-bundle.ts +26 -0
  382. package/src/workers/index.ts +165 -0
  383. package/src/workers/psbt-parallel.ts +332 -0
  384. package/src/workers/signing-worker.ts +353 -0
  385. package/src/workers/types.ts +413 -0
  386. package/test/address.spec.ts +9 -6
  387. package/test/bitcoin.core.spec.ts +16 -17
  388. package/test/block.spec.ts +8 -7
  389. package/test/bufferutils.spec.ts +228 -214
  390. package/test/crypto.spec.ts +19 -11
  391. package/test/fixtures/p2pk.json +0 -8
  392. package/test/fixtures/p2pkh.json +1 -1
  393. package/test/fixtures/p2sh.json +1 -1
  394. package/test/fixtures/script.json +1 -1
  395. package/test/fixtures/transaction.json +2 -2
  396. package/test/integration/_regtest.ts +25 -0
  397. package/test/integration/addresses.spec.ts +4 -3
  398. package/test/integration/bip32.spec.ts +2 -1
  399. package/test/integration/blocks.spec.ts +1 -1
  400. package/test/integration/cltv.spec.ts +18 -16
  401. package/test/integration/csv.spec.ts +37 -64
  402. package/test/integration/payments.spec.ts +5 -3
  403. package/test/integration/taproot.spec.ts +76 -83
  404. package/test/integration/transactions.spec.ts +38 -35
  405. package/test/payments.spec.ts +35 -13
  406. package/test/payments.utils.ts +17 -16
  407. package/test/psbt.spec.ts +111 -100
  408. package/test/script.spec.ts +11 -10
  409. package/test/script_signature.spec.ts +9 -11
  410. package/test/taproot-cache.spec.ts +694 -0
  411. package/test/transaction.spec.ts +32 -40
  412. package/test/types.spec.ts +74 -29
  413. package/test/workers-pool.spec.ts +963 -0
  414. package/test/workers-signing.spec.ts +635 -0
  415. package/test/workers.spec.ts +1390 -0
  416. package/tsconfig.base.json +34 -18
  417. package/tsconfig.browser.json +15 -0
  418. package/tsconfig.build.json +5 -0
  419. package/tsconfig.json +5 -14
  420. package/vite.config.browser.ts +3 -42
  421. package/vitest.config.integration.ts +2 -0
  422. package/browser/bufferutils.d.ts +0 -34
  423. package/browser/chunks/crypto-BhCpKpek.js +0 -2033
  424. package/browser/chunks/payments-B1wlSccx.js +0 -1089
  425. package/browser/chunks/psbt-BCNk7JUx.js +0 -4055
  426. package/browser/chunks/script-DyPItFEl.js +0 -318
  427. package/browser/chunks/transaction-C_UbhMGn.js +0 -432
  428. package/browser/chunks/utils-DNZi-T5W.js +0 -761
  429. package/browser/ecc_lib.d.ts +0 -3
  430. package/browser/hooks/AdvancedSignatureManager.d.ts +0 -16
  431. package/browser/hooks/HookedSigner.d.ts +0 -4
  432. package/browser/hooks/SignatureManager.d.ts +0 -13
  433. package/browser/payments/lazy.d.ts +0 -2
  434. package/browser/typeforce.d.ts +0 -38
  435. package/build/bufferutils.d.ts +0 -34
  436. package/build/bufferutils.js +0 -141
  437. package/build/ecc_lib.d.ts +0 -3
  438. package/build/ecc_lib.js +0 -61
  439. package/build/hooks/AdvancedSignatureManager.d.ts +0 -16
  440. package/build/hooks/AdvancedSignatureManager.js +0 -52
  441. package/build/hooks/HookedSigner.d.ts +0 -4
  442. package/build/hooks/HookedSigner.js +0 -64
  443. package/build/hooks/SignatureManager.d.ts +0 -13
  444. package/build/hooks/SignatureManager.js +0 -45
  445. package/build/payments/lazy.d.ts +0 -2
  446. package/build/payments/lazy.js +0 -28
  447. package/build/tsconfig.tsbuildinfo +0 -1
  448. package/src/bufferutils.ts +0 -188
  449. package/src/ecc_lib.ts +0 -94
  450. package/src/hooks/AdvancedSignatureManager.ts +0 -104
  451. package/src/hooks/HookedSigner.ts +0 -108
  452. package/src/hooks/SignatureManager.ts +0 -84
  453. package/src/payments/lazy.ts +0 -28
  454. package/src/typeforce.d.ts +0 -38
  455. package/tsconfig.webpack.json +0 -18
@@ -0,0 +1,963 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
2
+ import {
3
+ SignatureType,
4
+ WorkerState,
5
+ type BatchSigningTaskResult,
6
+ type SigningTask,
7
+ type ParallelSignerKeyPair,
8
+ type WorkerResponse,
9
+ type SigningResultMessage,
10
+ type WorkerPoolConfig,
11
+ } from '../src/workers/types.js';
12
+
13
+ // Mock Worker class for browser pool testing
14
+ class MockWorker {
15
+ public onmessage: ((event: { data: WorkerResponse }) => void) | null = null;
16
+ public onerror: ((error: Error) => void) | null = null;
17
+ private messageHandlers: Array<(event: { data: WorkerResponse }) => void> = [];
18
+ private errorHandlers: Array<(error: Error) => void> = [];
19
+ private terminated = false;
20
+
21
+ constructor(
22
+ public readonly url: string,
23
+ public readonly options?: { name?: string },
24
+ ) {
25
+ // Simulate async ready after construction
26
+ setTimeout(() => {
27
+ if (!this.terminated) {
28
+ this.simulateMessage({ type: 'ready' });
29
+ }
30
+ }, 5);
31
+ }
32
+
33
+ postMessage(data: unknown): void {
34
+ if (this.terminated) return;
35
+
36
+ const msg = data as { type: string; taskId?: string; privateKey?: Uint8Array };
37
+
38
+ if (msg.type === 'init') {
39
+ // Already sent ready in constructor
40
+ } else if (msg.type === 'signBatch') {
41
+ // Simulate batch signing - zero the key and return results
42
+ setTimeout(() => {
43
+ if (this.terminated) return;
44
+
45
+ const batchMsg = data as {
46
+ batchId: string;
47
+ tasks: Array<{
48
+ taskId: string;
49
+ inputIndex: number;
50
+ publicKey: Uint8Array;
51
+ signatureType: SignatureType;
52
+ leafHash?: Uint8Array;
53
+ }>;
54
+ privateKey?: Uint8Array;
55
+ };
56
+
57
+ // Zero the private key (simulating what worker does)
58
+ if (batchMsg.privateKey) {
59
+ batchMsg.privateKey.fill(0);
60
+ }
61
+
62
+ // Generate results for all tasks
63
+ const results = batchMsg.tasks.map((task): BatchSigningTaskResult => ({
64
+ taskId: task.taskId,
65
+ signature: new Uint8Array(64).fill(0xab),
66
+ inputIndex: task.inputIndex,
67
+ publicKey: task.publicKey,
68
+ signatureType: task.signatureType,
69
+ ...(task.leafHash ? { leafHash: task.leafHash } : {}),
70
+ }));
71
+
72
+ this.simulateMessage({
73
+ type: 'batchResult',
74
+ batchId: batchMsg.batchId,
75
+ results,
76
+ errors: [],
77
+ });
78
+ }, 10);
79
+ } else if (msg.type === 'shutdown') {
80
+ setTimeout(() => {
81
+ this.simulateMessage({ type: 'shutdown-ack' });
82
+ }, 5);
83
+ }
84
+ }
85
+
86
+ addEventListener(event: string, handler: (event: { data: WorkerResponse }) => void): void {
87
+ if (event === 'message') {
88
+ this.messageHandlers.push(handler);
89
+ } else if (event === 'error') {
90
+ this.errorHandlers.push(handler as unknown as (error: Error) => void);
91
+ }
92
+ }
93
+
94
+ removeEventListener(event: string, handler: (event: { data: WorkerResponse }) => void): void {
95
+ if (event === 'message') {
96
+ const idx = this.messageHandlers.indexOf(handler);
97
+ if (idx >= 0) this.messageHandlers.splice(idx, 1);
98
+ }
99
+ }
100
+
101
+ terminate(): void {
102
+ this.terminated = true;
103
+ this.messageHandlers = [];
104
+ this.errorHandlers = [];
105
+ }
106
+
107
+ private simulateMessage(data: WorkerResponse): void {
108
+ const event = { data };
109
+ if (this.onmessage) {
110
+ this.onmessage(event);
111
+ }
112
+ for (const handler of this.messageHandlers) {
113
+ handler(event);
114
+ }
115
+ }
116
+
117
+ simulateError(error: Error): void {
118
+ if (this.onerror) {
119
+ this.onerror(error);
120
+ }
121
+ for (const handler of this.errorHandlers) {
122
+ handler(error);
123
+ }
124
+ }
125
+ }
126
+
127
+ // Mock Worker that fails signing
128
+ class MockFailingWorker extends MockWorker {
129
+ postMessage(data: unknown): void {
130
+ if ((data as { type: string }).type === 'signBatch') {
131
+ setTimeout(() => {
132
+ const batchMsg = data as {
133
+ batchId: string;
134
+ tasks: Array<{
135
+ taskId: string;
136
+ inputIndex: number;
137
+ }>;
138
+ privateKey?: Uint8Array;
139
+ };
140
+ // Zero key even on failure
141
+ if (batchMsg.privateKey) {
142
+ batchMsg.privateKey.fill(0);
143
+ }
144
+ // Return errors for all tasks
145
+ const errors = batchMsg.tasks.map((task) => ({
146
+ taskId: task.taskId,
147
+ inputIndex: task.inputIndex,
148
+ error: 'Mock signing failure',
149
+ }));
150
+ this['simulateMessage']({
151
+ type: 'batchResult',
152
+ batchId: batchMsg.batchId,
153
+ results: [],
154
+ errors,
155
+ });
156
+ }, 10);
157
+ } else {
158
+ super.postMessage(data);
159
+ }
160
+ }
161
+ }
162
+
163
+ // Mock Worker that times out (never responds)
164
+ class MockTimeoutWorker extends MockWorker {
165
+ postMessage(data: unknown): void {
166
+ if ((data as { type: string }).type === 'signBatch') {
167
+ // Never respond - simulates timeout
168
+ // Still zero the key for security
169
+ const batchMsg = data as { privateKey?: Uint8Array };
170
+ if (batchMsg.privateKey) {
171
+ batchMsg.privateKey.fill(0);
172
+ }
173
+ } else {
174
+ super.postMessage(data);
175
+ }
176
+ }
177
+ }
178
+
179
+ // Mock URL for blob creation
180
+ const mockBlobUrls: string[] = [];
181
+ let blobUrlCounter = 0;
182
+
183
+ // Setup global mocks
184
+ beforeEach(() => {
185
+ // Mock URL.createObjectURL and URL.revokeObjectURL
186
+ if (typeof globalThis.URL === 'undefined') {
187
+ (globalThis as any).URL = class {
188
+ constructor(public href: string) {}
189
+ };
190
+ }
191
+
192
+ (globalThis.URL as any).createObjectURL = vi.fn((blob: Blob) => {
193
+ const url = `blob:mock-${blobUrlCounter++}`;
194
+ mockBlobUrls.push(url);
195
+ return url;
196
+ });
197
+
198
+ (globalThis.URL as any).revokeObjectURL = vi.fn((url: string) => {
199
+ const idx = mockBlobUrls.indexOf(url);
200
+ if (idx >= 0) mockBlobUrls.splice(idx, 1);
201
+ });
202
+
203
+ // Mock Blob
204
+ if (typeof globalThis.Blob === 'undefined') {
205
+ (globalThis as any).Blob = class {
206
+ constructor(
207
+ public parts: string[],
208
+ public options?: { type: string },
209
+ ) {}
210
+ };
211
+ }
212
+
213
+ // Mock Worker
214
+ (globalThis as any).Worker = MockWorker;
215
+ });
216
+
217
+ afterEach(() => {
218
+ vi.restoreAllMocks();
219
+ mockBlobUrls.length = 0;
220
+ });
221
+
222
+ describe('WorkerSigningPool', () => {
223
+ // Import dynamically after mocks are set up
224
+ let WorkerSigningPool: typeof import('../src/workers/WorkerSigningPool.js').WorkerSigningPool;
225
+ let getSigningPool: typeof import('../src/workers/WorkerSigningPool.js').getSigningPool;
226
+
227
+ beforeEach(async () => {
228
+ // Reset module cache to pick up mocks
229
+ vi.resetModules();
230
+ const module = await import('../src/workers/WorkerSigningPool.js');
231
+ WorkerSigningPool = module.WorkerSigningPool;
232
+ getSigningPool = module.getSigningPool;
233
+
234
+ // Reset singleton
235
+ WorkerSigningPool.resetInstance();
236
+ });
237
+
238
+ afterEach(async () => {
239
+ // Ensure pool is shut down
240
+ try {
241
+ const pool = WorkerSigningPool.getInstance();
242
+ await pool.shutdown();
243
+ } catch {
244
+ // Ignore
245
+ }
246
+ WorkerSigningPool.resetInstance();
247
+ });
248
+
249
+ describe('Singleton Pattern', () => {
250
+ it('should return same instance on multiple calls', () => {
251
+ const pool1 = WorkerSigningPool.getInstance();
252
+ const pool2 = WorkerSigningPool.getInstance();
253
+ expect(pool1).toBe(pool2);
254
+ });
255
+
256
+ it('should return same instance via getSigningPool helper', () => {
257
+ const pool1 = getSigningPool();
258
+ const pool2 = WorkerSigningPool.getInstance();
259
+ expect(pool1).toBe(pool2);
260
+ });
261
+
262
+ it('should create new instance after reset', () => {
263
+ const pool1 = WorkerSigningPool.getInstance();
264
+ WorkerSigningPool.resetInstance();
265
+ const pool2 = WorkerSigningPool.getInstance();
266
+ expect(pool1).not.toBe(pool2);
267
+ });
268
+
269
+ it('should accept config on first call', () => {
270
+ const pool = WorkerSigningPool.getInstance({ workerCount: 8 });
271
+ expect(pool).toBeDefined();
272
+ });
273
+ });
274
+
275
+ describe('Initialization', () => {
276
+ it('should initialize without error', async () => {
277
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
278
+ await expect(pool.initialize()).resolves.toBeUndefined();
279
+ });
280
+
281
+ it('should be idempotent', async () => {
282
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
283
+ await pool.initialize();
284
+ await pool.initialize(); // Second call should be no-op
285
+ expect(pool.workerCount).toBe(2);
286
+ });
287
+
288
+ it('should create specified number of workers', async () => {
289
+ const pool = WorkerSigningPool.getInstance({ workerCount: 4 });
290
+ await pool.initialize();
291
+ expect(pool.workerCount).toBe(4);
292
+ });
293
+
294
+ it('should have all workers idle after init', async () => {
295
+ const pool = WorkerSigningPool.getInstance({ workerCount: 3 });
296
+ await pool.initialize();
297
+ expect(pool.idleWorkerCount).toBe(3);
298
+ expect(pool.busyWorkerCount).toBe(0);
299
+ });
300
+ });
301
+
302
+ describe('Worker Preservation', () => {
303
+ it('should not preserve workers by default', () => {
304
+ const pool = WorkerSigningPool.getInstance();
305
+ expect(pool.isPreservingWorkers).toBe(false);
306
+ });
307
+
308
+ it('should preserve workers when enabled', () => {
309
+ const pool = WorkerSigningPool.getInstance();
310
+ pool.preserveWorkers();
311
+ expect(pool.isPreservingWorkers).toBe(true);
312
+ });
313
+
314
+ it('should release workers when disabled', () => {
315
+ const pool = WorkerSigningPool.getInstance();
316
+ pool.preserveWorkers();
317
+ expect(pool.isPreservingWorkers).toBe(true);
318
+ pool.releaseWorkers();
319
+ expect(pool.isPreservingWorkers).toBe(false);
320
+ });
321
+ });
322
+
323
+ describe('Signing Batches', () => {
324
+ it('should sign empty batch successfully', async () => {
325
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
326
+ pool.preserveWorkers();
327
+
328
+ const keyPair: ParallelSignerKeyPair = {
329
+ publicKey: new Uint8Array(33).fill(0x02),
330
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
331
+ };
332
+
333
+ const result = await pool.signBatch([], keyPair);
334
+
335
+ expect(result.success).toBe(true);
336
+ expect(result.signatures.size).toBe(0);
337
+ expect(result.errors.size).toBe(0);
338
+ });
339
+
340
+ it('should sign single task', async () => {
341
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
342
+ pool.preserveWorkers();
343
+
344
+ const keyPair: ParallelSignerKeyPair = {
345
+ publicKey: new Uint8Array(33).fill(0x02),
346
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
347
+ };
348
+
349
+ const tasks: SigningTask[] = [
350
+ {
351
+ taskId: 'task-0',
352
+ inputIndex: 0,
353
+ hash: new Uint8Array(32).fill(0x11),
354
+ signatureType: SignatureType.ECDSA,
355
+ sighashType: 0x01,
356
+ },
357
+ ];
358
+
359
+ const result = await pool.signBatch(tasks, keyPair);
360
+
361
+ expect(result.success).toBe(true);
362
+ expect(result.signatures.size).toBe(1);
363
+ expect(result.signatures.has(0)).toBe(true);
364
+ expect(result.errors.size).toBe(0);
365
+ });
366
+
367
+ it('should sign multiple tasks in parallel', async () => {
368
+ const pool = WorkerSigningPool.getInstance({ workerCount: 4 });
369
+ pool.preserveWorkers();
370
+
371
+ const keyPair: ParallelSignerKeyPair = {
372
+ publicKey: new Uint8Array(33).fill(0x02),
373
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
374
+ };
375
+
376
+ const tasks: SigningTask[] = [];
377
+ for (let i = 0; i < 10; i++) {
378
+ tasks.push({
379
+ taskId: `task-${i}`,
380
+ inputIndex: i,
381
+ hash: new Uint8Array(32).fill(i),
382
+ signatureType: SignatureType.ECDSA,
383
+ sighashType: 0x01,
384
+ });
385
+ }
386
+
387
+ const result = await pool.signBatch(tasks, keyPair);
388
+
389
+ expect(result.success).toBe(true);
390
+ expect(result.signatures.size).toBe(10);
391
+ expect(result.errors.size).toBe(0);
392
+
393
+ // Verify all signatures present
394
+ for (let i = 0; i < 10; i++) {
395
+ expect(result.signatures.has(i)).toBe(true);
396
+ }
397
+ });
398
+
399
+ it('should handle Schnorr signatures', async () => {
400
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
401
+ pool.preserveWorkers();
402
+
403
+ const keyPair: ParallelSignerKeyPair = {
404
+ publicKey: new Uint8Array(32).fill(0x02),
405
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
406
+ };
407
+
408
+ const tasks: SigningTask[] = [
409
+ {
410
+ taskId: 'schnorr-0',
411
+ inputIndex: 0,
412
+ hash: new Uint8Array(32),
413
+ signatureType: SignatureType.Schnorr,
414
+ sighashType: 0x00,
415
+ },
416
+ ];
417
+
418
+ const result = await pool.signBatch(tasks, keyPair);
419
+
420
+ expect(result.success).toBe(true);
421
+ expect(result.signatures.get(0)?.signatureType).toBe(SignatureType.Schnorr);
422
+ });
423
+
424
+ it('should handle mixed ECDSA and Schnorr', async () => {
425
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
426
+ pool.preserveWorkers();
427
+
428
+ const keyPair: ParallelSignerKeyPair = {
429
+ publicKey: new Uint8Array(33).fill(0x02),
430
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
431
+ };
432
+
433
+ const tasks: SigningTask[] = [
434
+ {
435
+ taskId: 'ecdsa-0',
436
+ inputIndex: 0,
437
+ hash: new Uint8Array(32),
438
+ signatureType: SignatureType.ECDSA,
439
+ sighashType: 0x01,
440
+ },
441
+ {
442
+ taskId: 'schnorr-1',
443
+ inputIndex: 1,
444
+ hash: new Uint8Array(32),
445
+ signatureType: SignatureType.Schnorr,
446
+ sighashType: 0x00,
447
+ },
448
+ ];
449
+
450
+ const result = await pool.signBatch(tasks, keyPair);
451
+
452
+ expect(result.success).toBe(true);
453
+ expect(result.signatures.get(0)?.signatureType).toBe(SignatureType.ECDSA);
454
+ expect(result.signatures.get(1)?.signatureType).toBe(SignatureType.Schnorr);
455
+ });
456
+
457
+ it('should include leafHash for Taproot script-path', async () => {
458
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
459
+ pool.preserveWorkers();
460
+
461
+ const leafHash = new Uint8Array(32).fill(0xcd);
462
+ const keyPair: ParallelSignerKeyPair = {
463
+ publicKey: new Uint8Array(32).fill(0x02),
464
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
465
+ };
466
+
467
+ const tasks: SigningTask[] = [
468
+ {
469
+ taskId: 'script-path-0',
470
+ inputIndex: 0,
471
+ hash: new Uint8Array(32),
472
+ signatureType: SignatureType.Schnorr,
473
+ sighashType: 0x00,
474
+ leafHash,
475
+ },
476
+ ];
477
+
478
+ const result = await pool.signBatch(tasks, keyPair);
479
+
480
+ expect(result.success).toBe(true);
481
+ expect(result.signatures.get(0)?.leafHash).toBeDefined();
482
+ });
483
+
484
+ it('should report duration', async () => {
485
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
486
+ pool.preserveWorkers();
487
+
488
+ const keyPair: ParallelSignerKeyPair = {
489
+ publicKey: new Uint8Array(33).fill(0x02),
490
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
491
+ };
492
+
493
+ const tasks: SigningTask[] = [
494
+ {
495
+ taskId: 'task-0',
496
+ inputIndex: 0,
497
+ hash: new Uint8Array(32),
498
+ signatureType: SignatureType.ECDSA,
499
+ sighashType: 0x01,
500
+ },
501
+ ];
502
+
503
+ const result = await pool.signBatch(tasks, keyPair);
504
+
505
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
506
+ });
507
+ });
508
+
509
+ describe('Key Security', () => {
510
+ it('should zero private key after signing', async () => {
511
+ const pool = WorkerSigningPool.getInstance({ workerCount: 1 });
512
+ pool.preserveWorkers();
513
+
514
+ let capturedKey: Uint8Array | null = null;
515
+ const keyPair: ParallelSignerKeyPair = {
516
+ publicKey: new Uint8Array(33).fill(0x02),
517
+ getPrivateKey: () => {
518
+ capturedKey = new Uint8Array(32).fill(0x42);
519
+ return capturedKey;
520
+ },
521
+ };
522
+
523
+ const tasks: SigningTask[] = [
524
+ {
525
+ taskId: 'task-0',
526
+ inputIndex: 0,
527
+ hash: new Uint8Array(32),
528
+ signatureType: SignatureType.ECDSA,
529
+ sighashType: 0x01,
530
+ },
531
+ ];
532
+
533
+ await pool.signBatch(tasks, keyPair);
534
+
535
+ // Key should be zeroed (both in worker and main thread)
536
+ expect(capturedKey).not.toBeNull();
537
+ expect(capturedKey!.every((b) => b === 0)).toBe(true);
538
+ });
539
+
540
+ it('should call getPrivateKey once per batch', async () => {
541
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
542
+ pool.preserveWorkers();
543
+
544
+ let callCount = 0;
545
+ const keyPair: ParallelSignerKeyPair = {
546
+ publicKey: new Uint8Array(33).fill(0x02),
547
+ getPrivateKey: () => {
548
+ callCount++;
549
+ return new Uint8Array(32).fill(0x42);
550
+ },
551
+ };
552
+
553
+ const tasks: SigningTask[] = [
554
+ {
555
+ taskId: 'task-0',
556
+ inputIndex: 0,
557
+ hash: new Uint8Array(32),
558
+ signatureType: SignatureType.ECDSA,
559
+ sighashType: 0x01,
560
+ },
561
+ {
562
+ taskId: 'task-1',
563
+ inputIndex: 1,
564
+ hash: new Uint8Array(32),
565
+ signatureType: SignatureType.ECDSA,
566
+ sighashType: 0x01,
567
+ },
568
+ ];
569
+
570
+ await pool.signBatch(tasks, keyPair);
571
+
572
+ // Batch signing obtains the key once and distributes to workers
573
+ expect(callCount).toBe(1);
574
+ });
575
+ });
576
+
577
+ describe('Shutdown', () => {
578
+ it('should shutdown gracefully', async () => {
579
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
580
+ await pool.initialize();
581
+ expect(pool.workerCount).toBe(2);
582
+
583
+ await pool.shutdown();
584
+ expect(pool.workerCount).toBe(0);
585
+ });
586
+
587
+ it('should be idempotent', async () => {
588
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
589
+ await pool.initialize();
590
+
591
+ await pool.shutdown();
592
+ await pool.shutdown(); // Second call should be no-op
593
+
594
+ expect(pool.workerCount).toBe(0);
595
+ });
596
+
597
+ it('should allow reinitialization after shutdown', async () => {
598
+ WorkerSigningPool.resetInstance();
599
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
600
+ await pool.initialize();
601
+ await pool.shutdown();
602
+
603
+ WorkerSigningPool.resetInstance();
604
+ const pool2 = WorkerSigningPool.getInstance({ workerCount: 3 });
605
+ await pool2.initialize();
606
+ expect(pool2.workerCount).toBe(3);
607
+ });
608
+ });
609
+
610
+ describe('Worker Pool Without Preservation', () => {
611
+ it('should terminate workers after batch when not preserving', async () => {
612
+ const pool = WorkerSigningPool.getInstance({ workerCount: 2 });
613
+ // Don't call preserveWorkers()
614
+
615
+ const keyPair: ParallelSignerKeyPair = {
616
+ publicKey: new Uint8Array(33).fill(0x02),
617
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
618
+ };
619
+
620
+ const tasks: SigningTask[] = [
621
+ {
622
+ taskId: 'task-0',
623
+ inputIndex: 0,
624
+ hash: new Uint8Array(32),
625
+ signatureType: SignatureType.ECDSA,
626
+ sighashType: 0x01,
627
+ },
628
+ ];
629
+
630
+ const result = await pool.signBatch(tasks, keyPair);
631
+ expect(result.success).toBe(true);
632
+
633
+ // Workers should be terminated after batch
634
+ // (In real implementation, idle workers are terminated)
635
+ });
636
+ });
637
+ });
638
+
639
+ describe('WorkerSigningPool Error Handling', () => {
640
+ let WorkerSigningPool: typeof import('../src/workers/WorkerSigningPool.js').WorkerSigningPool;
641
+
642
+ beforeEach(async () => {
643
+ vi.resetModules();
644
+
645
+ // Use failing worker
646
+ (globalThis as any).Worker = MockFailingWorker;
647
+
648
+ const module = await import('../src/workers/WorkerSigningPool.js');
649
+ WorkerSigningPool = module.WorkerSigningPool;
650
+ WorkerSigningPool.resetInstance();
651
+ });
652
+
653
+ afterEach(async () => {
654
+ try {
655
+ await WorkerSigningPool.getInstance().shutdown();
656
+ } catch {
657
+ // Ignore
658
+ }
659
+ WorkerSigningPool.resetInstance();
660
+ });
661
+
662
+ it('should handle signing failures', async () => {
663
+ const pool = WorkerSigningPool.getInstance({ workerCount: 1 });
664
+ pool.preserveWorkers();
665
+
666
+ const keyPair: ParallelSignerKeyPair = {
667
+ publicKey: new Uint8Array(33).fill(0x02),
668
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
669
+ };
670
+
671
+ const tasks: SigningTask[] = [
672
+ {
673
+ taskId: 'task-0',
674
+ inputIndex: 0,
675
+ hash: new Uint8Array(32),
676
+ signatureType: SignatureType.ECDSA,
677
+ sighashType: 0x01,
678
+ },
679
+ ];
680
+
681
+ const result = await pool.signBatch(tasks, keyPair);
682
+
683
+ expect(result.success).toBe(false);
684
+ expect(result.errors.size).toBe(1);
685
+ expect(result.errors.get(0)).toBe('Mock signing failure');
686
+ });
687
+
688
+ it('should handle partial failures in batch', async () => {
689
+ // Reset to use regular worker for first call
690
+ vi.resetModules();
691
+
692
+ class MixedWorker extends MockWorker {
693
+ postMessage(data: unknown): void {
694
+ if ((data as { type: string }).type === 'signBatch') {
695
+ setTimeout(() => {
696
+ const batchMsg = data as {
697
+ batchId: string;
698
+ tasks: Array<{
699
+ taskId: string;
700
+ inputIndex: number;
701
+ publicKey: Uint8Array;
702
+ signatureType: SignatureType;
703
+ leafHash?: Uint8Array;
704
+ }>;
705
+ privateKey?: Uint8Array;
706
+ };
707
+ if (batchMsg.privateKey) batchMsg.privateKey.fill(0);
708
+
709
+ // Fail every other task
710
+ const results: BatchSigningTaskResult[] = [];
711
+ const errors: Array<{
712
+ taskId: string;
713
+ inputIndex: number;
714
+ error: string;
715
+ }> = [];
716
+
717
+ batchMsg.tasks.forEach((task, idx) => {
718
+ if (idx % 2 === 0) {
719
+ results.push({
720
+ taskId: task.taskId,
721
+ signature: new Uint8Array(64).fill(0xab),
722
+ inputIndex: task.inputIndex,
723
+ publicKey: task.publicKey,
724
+ signatureType: task.signatureType as SignatureType,
725
+ ...(task.leafHash ? { leafHash: task.leafHash } : {}),
726
+ });
727
+ } else {
728
+ errors.push({
729
+ taskId: task.taskId,
730
+ inputIndex: task.inputIndex,
731
+ error: 'Simulated failure',
732
+ });
733
+ }
734
+ });
735
+
736
+ this['simulateMessage']({
737
+ type: 'batchResult',
738
+ batchId: batchMsg.batchId,
739
+ results,
740
+ errors,
741
+ });
742
+ }, 10);
743
+ } else {
744
+ super.postMessage(data);
745
+ }
746
+ }
747
+ }
748
+
749
+ (globalThis as any).Worker = MixedWorker;
750
+
751
+ const module = await import('../src/workers/WorkerSigningPool.js');
752
+ const pool = module.WorkerSigningPool.getInstance({ workerCount: 2 });
753
+ pool.preserveWorkers();
754
+
755
+ const keyPair: ParallelSignerKeyPair = {
756
+ publicKey: new Uint8Array(33).fill(0x02),
757
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
758
+ };
759
+
760
+ const tasks: SigningTask[] = [
761
+ {
762
+ taskId: 'task-0',
763
+ inputIndex: 0,
764
+ hash: new Uint8Array(32),
765
+ signatureType: SignatureType.ECDSA,
766
+ sighashType: 0x01,
767
+ },
768
+ {
769
+ taskId: 'task-1',
770
+ inputIndex: 1,
771
+ hash: new Uint8Array(32),
772
+ signatureType: SignatureType.ECDSA,
773
+ sighashType: 0x01,
774
+ },
775
+ {
776
+ taskId: 'task-2',
777
+ inputIndex: 2,
778
+ hash: new Uint8Array(32),
779
+ signatureType: SignatureType.ECDSA,
780
+ sighashType: 0x01,
781
+ },
782
+ {
783
+ taskId: 'task-3',
784
+ inputIndex: 3,
785
+ hash: new Uint8Array(32),
786
+ signatureType: SignatureType.ECDSA,
787
+ sighashType: 0x01,
788
+ },
789
+ ];
790
+
791
+ const result = await pool.signBatch(tasks, keyPair);
792
+
793
+ expect(result.success).toBe(false);
794
+ expect(result.signatures.size).toBe(2); // Half succeeded
795
+ expect(result.errors.size).toBe(2); // Half failed
796
+
797
+ await pool.shutdown();
798
+ module.WorkerSigningPool.resetInstance();
799
+ });
800
+ });
801
+
802
+ describe('WorkerSigningPool Timeout Handling', () => {
803
+ let WorkerSigningPool: typeof import('../src/workers/WorkerSigningPool.js').WorkerSigningPool;
804
+
805
+ beforeEach(async () => {
806
+ vi.resetModules();
807
+
808
+ // Use timeout worker
809
+ (globalThis as any).Worker = MockTimeoutWorker;
810
+
811
+ const module = await import('../src/workers/WorkerSigningPool.js');
812
+ WorkerSigningPool = module.WorkerSigningPool;
813
+ WorkerSigningPool.resetInstance();
814
+ });
815
+
816
+ afterEach(async () => {
817
+ try {
818
+ await WorkerSigningPool.getInstance().shutdown();
819
+ } catch {
820
+ // Ignore
821
+ }
822
+ WorkerSigningPool.resetInstance();
823
+ });
824
+
825
+ it('should timeout long-running tasks', async () => {
826
+ const pool = WorkerSigningPool.getInstance({
827
+ workerCount: 1,
828
+ maxKeyHoldTimeMs: 50, // Very short timeout for testing
829
+ });
830
+ pool.preserveWorkers();
831
+
832
+ const keyPair: ParallelSignerKeyPair = {
833
+ publicKey: new Uint8Array(33).fill(0x02),
834
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
835
+ };
836
+
837
+ const tasks: SigningTask[] = [
838
+ {
839
+ taskId: 'timeout-task',
840
+ inputIndex: 0,
841
+ hash: new Uint8Array(32),
842
+ signatureType: SignatureType.ECDSA,
843
+ sighashType: 0x01,
844
+ },
845
+ ];
846
+
847
+ const result = await pool.signBatch(tasks, keyPair);
848
+
849
+ expect(result.success).toBe(false);
850
+ expect(result.errors.size).toBe(1);
851
+ expect(result.errors.get(0)).toContain('timeout');
852
+ }, 10000);
853
+ });
854
+
855
+ describe('Concurrent Batch Operations', () => {
856
+ let WorkerSigningPool: typeof import('../src/workers/WorkerSigningPool.js').WorkerSigningPool;
857
+
858
+ beforeEach(async () => {
859
+ vi.resetModules();
860
+ (globalThis as any).Worker = MockWorker;
861
+
862
+ const module = await import('../src/workers/WorkerSigningPool.js');
863
+ WorkerSigningPool = module.WorkerSigningPool;
864
+ WorkerSigningPool.resetInstance();
865
+ });
866
+
867
+ afterEach(async () => {
868
+ try {
869
+ await WorkerSigningPool.getInstance().shutdown();
870
+ } catch {
871
+ // Ignore
872
+ }
873
+ WorkerSigningPool.resetInstance();
874
+ });
875
+
876
+ it('should handle concurrent signBatch calls', async () => {
877
+ const pool = WorkerSigningPool.getInstance({ workerCount: 4 });
878
+ pool.preserveWorkers();
879
+
880
+ const keyPair: ParallelSignerKeyPair = {
881
+ publicKey: new Uint8Array(33).fill(0x02),
882
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
883
+ };
884
+
885
+ const createTasks = (prefix: string, count: number): SigningTask[] => {
886
+ const tasks: SigningTask[] = [];
887
+ for (let i = 0; i < count; i++) {
888
+ tasks.push({
889
+ taskId: `${prefix}-${i}`,
890
+ inputIndex: i,
891
+ hash: new Uint8Array(32).fill(i),
892
+ signatureType: SignatureType.ECDSA,
893
+ sighashType: 0x01,
894
+ });
895
+ }
896
+ return tasks;
897
+ };
898
+
899
+ // Start multiple batches concurrently
900
+ const [result1, result2, result3] = await Promise.all([
901
+ pool.signBatch(createTasks('batch1', 5), keyPair),
902
+ pool.signBatch(createTasks('batch2', 5), keyPair),
903
+ pool.signBatch(createTasks('batch3', 5), keyPair),
904
+ ]);
905
+
906
+ expect(result1.success).toBe(true);
907
+ expect(result2.success).toBe(true);
908
+ expect(result3.success).toBe(true);
909
+
910
+ expect(result1.signatures.size).toBe(5);
911
+ expect(result2.signatures.size).toBe(5);
912
+ expect(result3.signatures.size).toBe(5);
913
+ });
914
+ });
915
+
916
+ describe('Large Batch Performance', () => {
917
+ let WorkerSigningPool: typeof import('../src/workers/WorkerSigningPool.js').WorkerSigningPool;
918
+
919
+ beforeEach(async () => {
920
+ vi.resetModules();
921
+ (globalThis as any).Worker = MockWorker;
922
+
923
+ const module = await import('../src/workers/WorkerSigningPool.js');
924
+ WorkerSigningPool = module.WorkerSigningPool;
925
+ WorkerSigningPool.resetInstance();
926
+ });
927
+
928
+ afterEach(async () => {
929
+ try {
930
+ await WorkerSigningPool.getInstance().shutdown();
931
+ } catch {
932
+ // Ignore
933
+ }
934
+ WorkerSigningPool.resetInstance();
935
+ });
936
+
937
+ it('should handle 100 inputs efficiently', async () => {
938
+ const pool = WorkerSigningPool.getInstance({ workerCount: 8 });
939
+ pool.preserveWorkers();
940
+
941
+ const keyPair: ParallelSignerKeyPair = {
942
+ publicKey: new Uint8Array(33).fill(0x02),
943
+ getPrivateKey: () => new Uint8Array(32).fill(0x42),
944
+ };
945
+
946
+ const tasks: SigningTask[] = [];
947
+ for (let i = 0; i < 100; i++) {
948
+ tasks.push({
949
+ taskId: `task-${i}`,
950
+ inputIndex: i,
951
+ hash: new Uint8Array(32).fill(i % 256),
952
+ signatureType: i % 2 === 0 ? SignatureType.ECDSA : SignatureType.Schnorr,
953
+ sighashType: i % 2 === 0 ? 0x01 : 0x00,
954
+ });
955
+ }
956
+
957
+ const result = await pool.signBatch(tasks, keyPair);
958
+
959
+ expect(result.success).toBe(true);
960
+ expect(result.signatures.size).toBe(100);
961
+ expect(result.errors.size).toBe(0);
962
+ }, 30000);
963
+ });