bitcoin-ruby 0.0.18 → 0.0.19

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 (255) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +46 -0
  5. data/.travis.yml +5 -1
  6. data/Gemfile +11 -9
  7. data/Gemfile.lock +64 -12
  8. data/README.rdoc +17 -4
  9. data/Rakefile +58 -83
  10. data/bitcoin-ruby.gemspec +5 -2
  11. data/lib/bitcoin.rb +31 -14
  12. data/lib/bitcoin/bech32.rb +126 -132
  13. data/lib/bitcoin/bloom_filter.rb +24 -21
  14. data/lib/bitcoin/builder.rb +168 -126
  15. data/lib/bitcoin/connection.rb +21 -24
  16. data/lib/bitcoin/contracthash.rb +20 -24
  17. data/lib/bitcoin/dogecoin.rb +79 -77
  18. data/lib/bitcoin/electrum/mnemonic.rb +28 -25
  19. data/lib/bitcoin/ext_key.rb +3 -3
  20. data/lib/bitcoin/ffi/bitcoinconsensus.rb +17 -13
  21. data/lib/bitcoin/ffi/openssl.rb +355 -338
  22. data/lib/bitcoin/ffi/secp256k1.rb +97 -64
  23. data/lib/bitcoin/protocol.rb +6 -3
  24. data/lib/bitcoin/protocol/address.rb +15 -13
  25. data/lib/bitcoin/protocol/aux_pow.rb +12 -15
  26. data/lib/bitcoin/protocol/block.rb +102 -76
  27. data/lib/bitcoin/protocol/handler.rb +2 -4
  28. data/lib/bitcoin/protocol/parser.rb +108 -92
  29. data/lib/bitcoin/protocol/partial_merkle_tree.rb +59 -47
  30. data/lib/bitcoin/protocol/reject.rb +26 -28
  31. data/lib/bitcoin/protocol/script_witness.rb +3 -8
  32. data/lib/bitcoin/protocol/tx.rb +250 -137
  33. data/lib/bitcoin/protocol/txin.rb +44 -38
  34. data/lib/bitcoin/protocol/txout.rb +27 -20
  35. data/lib/bitcoin/protocol/version.rb +47 -34
  36. data/lib/bitcoin/script.rb +18 -17
  37. data/lib/bitcoin/trezor/mnemonic.rb +113 -98
  38. data/lib/bitcoin/version.rb +1 -1
  39. data/spec/examples.txt +399 -0
  40. data/spec/{bitcoin/fixtures → fixtures}/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +0 -0
  41. data/spec/{bitcoin/fixtures → fixtures}/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +0 -0
  42. data/spec/{bitcoin/fixtures → fixtures}/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +0 -0
  43. data/spec/{bitcoin/fixtures → fixtures}/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +0 -0
  44. data/spec/{bitcoin/fixtures → fixtures}/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +0 -0
  45. data/spec/{bitcoin/fixtures → fixtures}/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +0 -0
  46. data/spec/{bitcoin/fixtures → fixtures}/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +0 -0
  47. data/spec/{bitcoin/fixtures → fixtures}/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +0 -0
  48. data/spec/{bitcoin/fixtures → fixtures}/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +0 -0
  49. data/spec/{bitcoin/fixtures → fixtures}/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +0 -0
  50. data/spec/{bitcoin/fixtures → fixtures}/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +0 -0
  51. data/spec/{bitcoin/fixtures → fixtures}/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +0 -0
  52. data/spec/{bitcoin/fixtures → fixtures}/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +0 -0
  53. data/spec/{bitcoin/fixtures → fixtures}/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +0 -0
  54. data/spec/{bitcoin/fixtures → fixtures}/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +0 -0
  55. data/spec/{bitcoin/fixtures → fixtures}/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +0 -0
  56. data/spec/{bitcoin/fixtures → fixtures}/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +0 -0
  57. data/spec/{bitcoin/fixtures → fixtures}/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +0 -0
  58. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_invalid.json +0 -0
  59. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_valid.json +0 -0
  60. data/spec/{bitcoin/fixtures → fixtures}/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +0 -0
  61. data/spec/{bitcoin/fixtures → fixtures}/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +0 -0
  62. data/spec/{bitcoin/fixtures → fixtures}/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  63. data/spec/{bitcoin/fixtures → fixtures}/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +0 -0
  64. data/spec/{bitcoin/fixtures → fixtures}/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +0 -0
  65. data/spec/{bitcoin/fixtures → fixtures}/coinbase-toshi.json +0 -0
  66. data/spec/{bitcoin/fixtures → fixtures}/coinbase.json +0 -0
  67. data/spec/{bitcoin/fixtures → fixtures}/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  68. data/spec/{bitcoin/fixtures → fixtures}/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +0 -0
  69. data/spec/{bitcoin/fixtures → fixtures}/filteredblock-0.bin +0 -0
  70. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  71. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +0 -0
  72. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  73. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +0 -0
  74. data/spec/{bitcoin/fixtures → fixtures}/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +0 -0
  75. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.bin +0 -0
  76. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.json +0 -0
  77. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.bin +0 -0
  78. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.json +0 -0
  79. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.bin +0 -0
  80. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.json +0 -0
  81. data/spec/{bitcoin/fixtures → fixtures}/rawblock-170.bin +0 -0
  82. data/spec/{bitcoin/fixtures → fixtures}/rawblock-9.bin +0 -0
  83. data/spec/{bitcoin/fixtures → fixtures}/rawblock-auxpow.bin +0 -0
  84. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-1151351.bin +0 -0
  85. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.bin +0 -0
  86. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.json +0 -0
  87. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-265322.bin +0 -0
  88. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01-toshi.json +0 -0
  89. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.bin +0 -0
  90. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.json +0 -0
  91. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02-toshi.json +0 -0
  92. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.bin +0 -0
  93. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.json +0 -0
  94. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03-toshi.json +0 -0
  95. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.bin +0 -0
  96. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.json +0 -0
  97. data/spec/{bitcoin/fixtures → fixtures}/rawtx-04.json +0 -0
  98. data/spec/{bitcoin/fixtures → fixtures}/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
  99. data/spec/{bitcoin/fixtures → fixtures}/rawtx-05.json +0 -0
  100. data/spec/{bitcoin/fixtures → fixtures}/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
  101. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
  102. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +0 -0
  103. data/spec/{bitcoin/fixtures → fixtures}/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +0 -0
  104. data/spec/{bitcoin/fixtures → fixtures}/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
  105. data/spec/{bitcoin/fixtures → fixtures}/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
  106. data/spec/{bitcoin/fixtures → fixtures}/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +0 -0
  107. data/spec/{bitcoin/fixtures → fixtures}/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +0 -0
  108. data/spec/{bitcoin/fixtures → fixtures}/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +0 -0
  109. data/spec/{bitcoin/fixtures → fixtures}/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
  110. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.bin +0 -0
  111. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.json +0 -0
  112. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  113. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  114. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  115. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  116. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +0 -0
  117. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  118. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
  119. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +0 -0
  120. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  121. data/spec/{bitcoin/fixtures → fixtures}/script_tests.json +0 -0
  122. data/spec/{bitcoin/fixtures → fixtures}/sighash.json +0 -0
  123. data/spec/{bitcoin/fixtures → fixtures}/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +0 -0
  124. data/spec/{bitcoin/fixtures → fixtures}/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +0 -0
  125. data/spec/{bitcoin/fixtures → fixtures}/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +0 -0
  126. data/spec/{bitcoin/fixtures → fixtures}/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +0 -0
  127. data/spec/{bitcoin/fixtures → fixtures}/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +0 -0
  128. data/spec/{bitcoin/fixtures → fixtures}/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +0 -0
  129. data/spec/{bitcoin/fixtures → fixtures}/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +0 -0
  130. data/spec/{bitcoin/fixtures → fixtures}/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +0 -0
  131. data/spec/{bitcoin/fixtures → fixtures}/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +0 -0
  132. data/spec/{bitcoin/fixtures → fixtures}/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +0 -0
  133. data/spec/{bitcoin/fixtures → fixtures}/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +0 -0
  134. data/spec/{bitcoin/fixtures → fixtures}/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +0 -0
  135. data/spec/{bitcoin/fixtures → fixtures}/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +0 -0
  136. data/spec/{bitcoin/fixtures → fixtures}/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +0 -0
  137. data/spec/{bitcoin/fixtures → fixtures}/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +0 -0
  138. data/spec/{bitcoin/fixtures → fixtures}/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +0 -0
  139. data/spec/{bitcoin/fixtures → fixtures}/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +0 -0
  140. data/spec/{bitcoin/fixtures → fixtures}/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +0 -0
  141. data/spec/{bitcoin/fixtures → fixtures}/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +0 -0
  142. data/spec/{bitcoin/fixtures → fixtures}/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +0 -0
  143. data/spec/{bitcoin/fixtures → fixtures}/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +0 -0
  144. data/spec/{bitcoin/fixtures → fixtures}/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +0 -0
  145. data/spec/{bitcoin/fixtures → fixtures}/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +0 -0
  146. data/spec/{bitcoin/fixtures → fixtures}/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +0 -0
  147. data/spec/{bitcoin/fixtures → fixtures}/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +0 -0
  148. data/spec/{bitcoin/fixtures → fixtures}/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +0 -0
  149. data/spec/{bitcoin/fixtures → fixtures}/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +0 -0
  150. data/spec/{bitcoin/fixtures → fixtures}/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +0 -0
  151. data/spec/{bitcoin/fixtures → fixtures}/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +0 -0
  152. data/spec/{bitcoin/fixtures → fixtures}/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +0 -0
  153. data/spec/{bitcoin/fixtures → fixtures}/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +0 -0
  154. data/spec/{bitcoin/fixtures → fixtures}/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +0 -0
  155. data/spec/{bitcoin/fixtures → fixtures}/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +0 -0
  156. data/spec/{bitcoin/fixtures → fixtures}/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +0 -0
  157. data/spec/{bitcoin/fixtures → fixtures}/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +0 -0
  158. data/spec/{bitcoin/fixtures → fixtures}/tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json +0 -0
  159. data/spec/{bitcoin/fixtures → fixtures}/tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json +0 -0
  160. data/spec/{bitcoin/fixtures → fixtures}/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +0 -0
  161. data/spec/{bitcoin/fixtures → fixtures}/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +0 -0
  162. data/spec/{bitcoin/fixtures → fixtures}/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +0 -0
  163. data/spec/{bitcoin/fixtures → fixtures}/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +0 -0
  164. data/spec/{bitcoin/fixtures → fixtures}/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +0 -0
  165. data/spec/{bitcoin/fixtures → fixtures}/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +0 -0
  166. data/spec/{bitcoin/fixtures → fixtures}/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +0 -0
  167. data/spec/{bitcoin/fixtures → fixtures}/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +0 -0
  168. data/spec/{bitcoin/fixtures → fixtures}/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +0 -0
  169. data/spec/{bitcoin/fixtures → fixtures}/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +0 -0
  170. data/spec/{bitcoin/fixtures → fixtures}/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +0 -0
  171. data/spec/{bitcoin/fixtures → fixtures}/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +0 -0
  172. data/spec/{bitcoin/fixtures → fixtures}/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +0 -0
  173. data/spec/{bitcoin/fixtures → fixtures}/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +0 -0
  174. data/spec/helpers/block_helpers.rb +58 -0
  175. data/spec/helpers/fixture_helpers.rb +20 -0
  176. data/spec/helpers/library_helpers.rb +15 -0
  177. data/spec/spec_helper.rb +109 -0
  178. data/spec/unit/bitcoin/bech32_spec.rb +187 -0
  179. data/spec/unit/bitcoin/bitcoin_spec.rb +1079 -0
  180. data/spec/unit/bitcoin/bloom_filter_spec.rb +33 -0
  181. data/spec/unit/bitcoin/builder_spec.rb +559 -0
  182. data/spec/unit/bitcoin/contracthash_spec.rb +52 -0
  183. data/spec/unit/bitcoin/ext_key_spec.rb +281 -0
  184. data/spec/unit/bitcoin/key_spec.rb +457 -0
  185. data/spec/unit/bitcoin/network_spec.rb +71 -0
  186. data/spec/unit/bitcoin/protocol/addr_spec.rb +90 -0
  187. data/spec/unit/bitcoin/protocol/aux_pow_spec.rb +45 -0
  188. data/spec/unit/bitcoin/protocol/bip143_spec.rb +334 -0
  189. data/spec/unit/bitcoin/protocol/block_spec.rb +280 -0
  190. data/spec/unit/bitcoin/protocol/getblocks_spec.rb +44 -0
  191. data/spec/unit/bitcoin/protocol/inv_spec.rb +166 -0
  192. data/spec/unit/bitcoin/protocol/notfound_spec.rb +44 -0
  193. data/spec/unit/bitcoin/protocol/parser_spec.rb +69 -0
  194. data/spec/unit/bitcoin/protocol/partial_merkle_tree_spec.rb +47 -0
  195. data/spec/unit/bitcoin/protocol/ping_spec.rb +62 -0
  196. data/spec/unit/bitcoin/protocol/tx_spec.rb +1515 -0
  197. data/spec/unit/bitcoin/protocol/txin_spec.rb +47 -0
  198. data/spec/unit/bitcoin/protocol/txout_spec.rb +36 -0
  199. data/spec/unit/bitcoin/protocol/version_spec.rb +121 -0
  200. data/spec/unit/bitcoin/script/opcodes_spec.rb +864 -0
  201. data/spec/unit/bitcoin/script/script_spec.rb +1610 -0
  202. data/spec/unit/bitcoin/secp256k1_spec.rb +138 -0
  203. data/spec/unit/bitcoin/trezor/mnemonic_spec.rb +193 -0
  204. data/spec/unit/integrations/dogecoin_spec.rb +215 -0
  205. metadata +381 -372
  206. data/lib/bitcoin/logger.rb +0 -86
  207. data/lib/bitcoin/protocol/alert.rb +0 -46
  208. data/spec/bitcoin/bech32_spec.rb +0 -160
  209. data/spec/bitcoin/bitcoin_spec.rb +0 -666
  210. data/spec/bitcoin/bloom_filter_spec.rb +0 -23
  211. data/spec/bitcoin/builder_spec.rb +0 -375
  212. data/spec/bitcoin/contracthash_spec.rb +0 -45
  213. data/spec/bitcoin/dogecoin_spec.rb +0 -176
  214. data/spec/bitcoin/ext_key_spec.rb +0 -180
  215. data/spec/bitcoin/ffi_openssl.rb +0 -45
  216. data/spec/bitcoin/fixtures/rawblock-170.json +0 -68
  217. data/spec/bitcoin/fixtures/rawblock-9.json +0 -39
  218. data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
  219. data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
  220. data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
  221. data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
  222. data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
  223. data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
  224. data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
  225. data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
  226. data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
  227. data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
  228. data/spec/bitcoin/fixtures/txdp-1.txt +0 -32
  229. data/spec/bitcoin/fixtures/txdp-2-signed.txt +0 -19
  230. data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +0 -14
  231. data/spec/bitcoin/helpers/fake_blockchain.rb +0 -183
  232. data/spec/bitcoin/key_spec.rb +0 -326
  233. data/spec/bitcoin/network_spec.rb +0 -50
  234. data/spec/bitcoin/performance/storage_spec.rb +0 -41
  235. data/spec/bitcoin/protocol/addr_spec.rb +0 -82
  236. data/spec/bitcoin/protocol/alert_spec.rb +0 -22
  237. data/spec/bitcoin/protocol/aux_pow_spec.rb +0 -45
  238. data/spec/bitcoin/protocol/bip143_spec.rb +0 -116
  239. data/spec/bitcoin/protocol/block_spec.rb +0 -208
  240. data/spec/bitcoin/protocol/getblocks_spec.rb +0 -32
  241. data/spec/bitcoin/protocol/inv_spec.rb +0 -134
  242. data/spec/bitcoin/protocol/notfound_spec.rb +0 -31
  243. data/spec/bitcoin/protocol/parser_spec.rb +0 -50
  244. data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +0 -38
  245. data/spec/bitcoin/protocol/ping_spec.rb +0 -51
  246. data/spec/bitcoin/protocol/reject.rb +0 -17
  247. data/spec/bitcoin/protocol/tx_spec.rb +0 -894
  248. data/spec/bitcoin/protocol/txin_spec.rb +0 -45
  249. data/spec/bitcoin/protocol/txout_spec.rb +0 -33
  250. data/spec/bitcoin/protocol/version_spec.rb +0 -110
  251. data/spec/bitcoin/script/opcodes_spec.rb +0 -773
  252. data/spec/bitcoin/script/script_spec.rb +0 -977
  253. data/spec/bitcoin/secp256k1_spec.rb +0 -78
  254. data/spec/bitcoin/spec_helper.rb +0 -108
  255. data/spec/bitcoin/trezor/mnemonic_spec.rb +0 -161
@@ -0,0 +1,44 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ describe 'Bitcoin::Protocol::Parser (notfound)' do
7
+ # Mock handler
8
+ class NotfoundHandler < Bitcoin::Protocol::Handler
9
+ attr_reader :notfound
10
+
11
+ def on_notfound(type, hash)
12
+ (@notfound ||= []) << [type, hash.hth]
13
+ end
14
+ end
15
+
16
+ let(:handler) { NotfoundHandler.new }
17
+ let(:parser) { Bitcoin::Protocol::Parser.new(handler) }
18
+
19
+ it 'parses notfound block message' do
20
+ payload = "\x01\x01\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n" \
21
+ "\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
22
+ expect(
23
+ parser.parse(Bitcoin::Protocol.pkt('notfound', payload) + 'AAAA')
24
+ ).to eq('AAAA')
25
+ expect(handler.notfound).to eq(
26
+ [
27
+ [:tx, '2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a']
28
+ ]
29
+ )
30
+ end
31
+
32
+ it 'parses notfound tx message' do
33
+ payload = "\x01\x02\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n" \
34
+ "\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
35
+ expect(
36
+ parser.parse(Bitcoin::Protocol.pkt('notfound', payload) + 'AAAA')
37
+ ).to eq('AAAA')
38
+ expect(handler.notfound).to eq(
39
+ [
40
+ [:block, '2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a']
41
+ ]
42
+ )
43
+ end
44
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Bitcoin::Protocol::Parser do
7
+ let(:pkt) do
8
+ [
9
+ 'f9 be b4 d9', # magic head
10
+ '69 6e 76 00 00 00 00 00 00 00 00 00', # command ('inv')
11
+ '49 00 00 00', # message length
12
+ '11 ea 1c 91', # checksum
13
+
14
+ '02', # n hashes
15
+ '01 00 00 00', # type (1=tx)
16
+ 'e0 41 c2 38 f7 32 1a 68 0a 34 06 bf fd 72 12 e3 d1 2c b5 12 2a 8c 0b ' \
17
+ '52 76 de 82 30 b1 00 7a 42',
18
+ '01 00 00 00', # type (1=tx)
19
+ '33 00 09 71 a9 70 7b 6c 6d 6e 77 aa 2e ac 43 f3 e5 67 84 cb 61 b2 35 ' \
20
+ 'fb 8d fe e0 86 8b 40 7c f3'
21
+ ].map { |s| s.split(' ') }.flatten.join.htb
22
+ end
23
+ let(:handler) { instance_double('Bitcoin::Protocol::Handler') }
24
+
25
+ it 'should call appropriate handler' do
26
+ expect(handler)
27
+ .to receive(:on_inv_transaction)
28
+ .and_return([pkt[29..60].reverse])
29
+ expect(handler)
30
+ .to receive(:on_inv_transaction)
31
+ .and_return([pkt[-32..-1].reverse])
32
+ expect(described_class.new(handler).parse(pkt)).to eq('')
33
+ end
34
+
35
+ it 'should count total packets and bytes' do
36
+ expect(handler)
37
+ .to receive(:on_inv_transaction)
38
+ .and_return([pkt[29..60].reverse])
39
+ expect(handler)
40
+ .to receive(:on_inv_transaction)
41
+ .and_return([pkt[-32..-1].reverse])
42
+
43
+ parser = described_class.new(handler)
44
+
45
+ parser.parse pkt
46
+ expect(parser.stats)
47
+ .to eq('total_packets' => 1,
48
+ 'total_bytes' => 73,
49
+ 'total_errors' => 0,
50
+ 'inv' => 1)
51
+ end
52
+
53
+ it 'should call error handler for unknown command' do
54
+ expect(handler)
55
+ .to receive(:on_error)
56
+ .with(:unknown_packet, %w[foo 626172])
57
+ expect(described_class.new(handler).process_pkt('foo', 'bar')).to be_nil
58
+ end
59
+
60
+ it 'should count total errors' do
61
+ expect(handler)
62
+ .to receive(:on_error)
63
+ .with(:unknown_packet, %w[foo 626172])
64
+
65
+ parser = described_class.new(handler)
66
+ parser.process_pkt('foo', 'bar')
67
+ expect(parser.stats['total_errors']).to eq(1)
68
+ end
69
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ # following test cases are borrowed from
7
+ # https://github.com/bitcoinj/bitcoinj/blob/master/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java
8
+ describe 'Bitcoin::Protocol::PartialMerkleTree' do
9
+ it 'initialize' do
10
+ hashes = %w[
11
+ 4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb
12
+ ca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb
13
+ bb15ac1d57d0182aaee61c74743a9c4f785895e563909bafec45c9a2b0ff3181
14
+ d77706be8b1dcc91112eada86d424e2d0a8907c3488b6e44fda5a74a25cbc7d6
15
+ bb4fa04245f4ac8a1a571d5537eac24adca1454d65eda446055479af6c6d4dd3
16
+ c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db6615c6abc5
17
+ ca042127bfaf9f44ebce29cb29c6df9d05b47f35b2edff4f0064b578ab741fa7
18
+ 8276222651209fe1a2c4c0fa1c58510aec8b090dd1eb1f82f9d261b8273b525b
19
+ ].map(&:htb)
20
+
21
+ tree = Bitcoin::Protocol::PartialMerkleTree.new(12, hashes, 'ff1a'.htb)
22
+ tree.assign_value
23
+
24
+ tx_hashes = Set.new(tree.tx_hashes)
25
+ # following 6 are leaves (tx_hash) of merkle tree
26
+ expect(tx_hashes)
27
+ .to include('bb28a1a5b3a02e7657a81c38355d56c6f05e80b9219432e3352ddcfc3cb6304c')
28
+ expect(tx_hashes)
29
+ .to include('fbde5d03b027d2b9ba4cf5d4fecab9a99864df2637b25ea4cbcb1796ff6550ca')
30
+ expect(tx_hashes)
31
+ .to include('8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb')
32
+ expect(tx_hashes)
33
+ .to include('c5abc61566dbb1c4bce5e1fda7b66bed22eb2130cea4b721690bc1488465abc9')
34
+ expect(tx_hashes)
35
+ .to include('d6c7cb254aa7a5fd446e8b48c307890a2d4e426da8ad2e1191cc1d8bbe0677d7')
36
+ expect(tx_hashes)
37
+ .to include('a71f74ab78b564004fffedb2357fb4059ddfc629cb29ceeb449fafbf272104ca')
38
+ # following 2 are edge node of merkle tree
39
+ expect(tx_hashes)
40
+ .not_to include('d34d6d6caf79540546a4ed654d45a1dc4ac2ea37551d571a8aacf44542a04fbb')
41
+ expect(tx_hashes)
42
+ .not_to include('5b523b27b861d2f9821febd10d098bec0a51581cfac0c4a2e19f205126227682')
43
+
44
+ expect(tree.root.value)
45
+ .to eq('7fe79307aeb300d910d9c4bec5bacb4c7e114c7dfd6789e19f3a733debb3bb6a')
46
+ end
47
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ describe 'Bitcoin::Protocol::Parser (ping/pong)' do
7
+ # Mock handler for ping and pong messages
8
+ class PingHandler < Bitcoin::Protocol::Handler
9
+ attr_reader :nonce
10
+
11
+ def on_ping(nonce)
12
+ @nonce = nonce
13
+ end
14
+
15
+ def on_pong(nonce)
16
+ @nonce = nonce
17
+ end
18
+ end
19
+
20
+ let(:handler) { PingHandler.new }
21
+ let(:parser) { Bitcoin::Protocol::Parser.new(handler) }
22
+
23
+ it 'parses ping without nonce' do
24
+ result = parser.parse(
25
+ Bitcoin::Protocol.pkt('ping', '') + 'AAAA'
26
+ )
27
+ expect(result).to eq('AAAA')
28
+ expect(handler.nonce).to be_nil
29
+ end
30
+
31
+ it 'parses ping with nonce' do
32
+ result = parser.parse(
33
+ Bitcoin::Protocol.pkt('ping', [12_345].pack('Q')) + 'AAAA'
34
+ )
35
+
36
+ expect(result).to eq('AAAA')
37
+ expect(handler.nonce).to eq(12_345)
38
+ end
39
+
40
+ it 'builds ping without nonce' do
41
+ parser.parse(Bitcoin::Protocol.ping_pkt)
42
+ expect(handler.nonce).not_to be_nil
43
+ end
44
+
45
+ it 'builds ping with nonce' do
46
+ parser.parse(Bitcoin::Protocol.ping_pkt(12_345))
47
+ expect(handler.nonce).to eq(12_345)
48
+ end
49
+
50
+ it 'parses pong' do
51
+ result = parser.parse(
52
+ Bitcoin::Protocol.pkt('pong', [12_345].pack('Q')) + 'AAAA'
53
+ )
54
+ expect(result).to eq('AAAA')
55
+ expect(handler.nonce).to eq(12_345)
56
+ end
57
+
58
+ it 'builds pong' do
59
+ parser.parse(Bitcoin::Protocol.pong_pkt(12_345))
60
+ expect(handler.nonce).to eq(12_345)
61
+ end
62
+ end
@@ -0,0 +1,1515 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Bitcoin::Protocol::Tx do
7
+ let(:payloads) do
8
+ [
9
+ fixtures_file('rawtx-01.bin'),
10
+ fixtures_file('rawtx-02.bin'),
11
+ fixtures_file('rawtx-03.bin'),
12
+ fixtures_file('rawtx-p2wpkh.bin')
13
+ ]
14
+ end
15
+
16
+ let(:json) do
17
+ [
18
+ fixtures_file('rawtx-01.json'),
19
+ fixtures_file('rawtx-02.json'),
20
+ fixtures_file('rawtx-03.json'),
21
+ fixtures_file('rawtx-p2wpkh.json')
22
+ ]
23
+ end
24
+
25
+ describe '#new' do
26
+ it 'does not raise an error for valid payloads' do
27
+ Bitcoin::Protocol::Tx.new(nil)
28
+ payloads.each { |payload| Bitcoin::Protocol::Tx.new(payload) }
29
+ end
30
+
31
+ it 'raises an error for an invalid payload' do
32
+ expect do
33
+ Bitcoin::Protocol::Tx.new(payloads[0][0..20])
34
+ end.to raise_error(NoMethodError, /undefined method `unpack'/)
35
+ end
36
+
37
+ it 'correctly deserializes a new, empty transaction' do
38
+ Bitcoin::Protocol::Tx.new(Bitcoin::Protocol::Tx.new.to_payload)
39
+ end
40
+ end
41
+
42
+ describe '#parse_data' do
43
+ let(:tx) { Bitcoin::Protocol::Tx.new(nil) }
44
+
45
+ it 'correctly parses payloads' do
46
+ expect(tx.hash).to be_nil
47
+ expect(tx.parse_data(payloads[0])).to be true
48
+ expect(tx.hash.size).to eq(64)
49
+ expect(tx.payload).to eq(payloads[0])
50
+ end
51
+
52
+ it 'parses additional payload data' do
53
+ expect(tx.parse_data(payloads[0] + 'AAAA')).to eq('AAAA')
54
+ expect(tx.hash.size).to eq(64)
55
+ expect(tx.payload).to eq(payloads[0])
56
+ end
57
+ end
58
+
59
+ describe '#parse_witness_data' do
60
+ it 'correctly parses witness data' do
61
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
62
+ expect(tx.hash.size).to eq(64)
63
+ expect(tx.payload).to eq(payloads[3])
64
+ end
65
+
66
+ it 'ignores additional payload data' do
67
+ tx = Bitcoin::Protocol::Tx.new(payloads[3] + 'AAAA')
68
+ expect(tx.hash.size).to eq(64)
69
+ expect(tx.payload).to eq(payloads[3])
70
+ end
71
+ end
72
+
73
+ describe '#hash' do
74
+ it 'produces the expected hash and binary hash' do
75
+ tx = Bitcoin::Protocol::Tx.new(payloads[0])
76
+ expect(tx.hash.size).to eq(64)
77
+ expect(tx.hash)
78
+ .to eq('6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4')
79
+ expect(tx.binary_hash)
80
+ .to eq("\xB4\x02-\x9F\xE5(\xFB\x90pP\x01\x16K\f\xC3\xA8\xF5\xA1\x9C" \
81
+ "\xB8\xED\x02\xBF\xD4\xFC,\xB6%f\xD1\x9Dn")
82
+
83
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
84
+ expect(tx.hash.size).to eq(64)
85
+ expect(tx.hash)
86
+ .to eq('f22f5168cf0bc55a31003b0fc532152da551e1ec4289c4fd92e7ec512c6e87a0')
87
+ end
88
+ end
89
+
90
+ describe '#witness_hash' do
91
+ it 'produces the expected witness hash' do
92
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
93
+ expect(tx.witness_hash.size).to eq(64)
94
+ expect(tx.witness_hash)
95
+ .to eq('c9609ed4d7e60ebcf4cce2854568b54a855a12b5bda15433ca96e72cd445a5cf')
96
+ end
97
+ end
98
+
99
+ describe '#normalized_hash' do
100
+ it 'produces the expected normalized hash' do
101
+ tx = Bitcoin::Protocol::Tx.new(payloads[0])
102
+ expect(tx.normalized_hash.size).to eq(64)
103
+ expect(tx.normalized_hash)
104
+ .to eq('393a12b91d5b5e2449f2d27a22ffc0af937c3796a08c8213cc37690b10302e40')
105
+
106
+ new_tx = JSON.parse(tx.to_json)
107
+ script = Bitcoin::Script.from_string(new_tx['in'][0]['scriptSig'])
108
+ script.chunks[0].bitcoin_pushdata = Bitcoin::Script::OP_PUSHDATA2
109
+ script.chunks[0].bitcoin_pushdata_length = script.chunks[0].bytesize
110
+ new_tx['in'][0]['scriptSig'] = script.to_string
111
+ new_tx = Bitcoin::Protocol::Tx.from_hash(new_tx, false)
112
+
113
+ expect(new_tx.hash).not_to eq(tx.hash)
114
+ expect(new_tx.normalized_hash.size).to eq(64)
115
+ expect(new_tx.normalized_hash)
116
+ .to eq('393a12b91d5b5e2449f2d27a22ffc0af937c3796a08c8213cc37690b10302e40')
117
+ end
118
+ end
119
+
120
+ describe '#to_payload' do
121
+ it 'produces the expected payloads' do
122
+ tx = Bitcoin::Protocol::Tx.new(payloads[0])
123
+ expect(tx.to_payload.size).to eq(payloads[0].size)
124
+ expect(tx.to_payload).to eq(payloads[0])
125
+ end
126
+ end
127
+
128
+ describe '#to_witness_payload' do
129
+ it 'produces the expected payloads' do
130
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
131
+ expect(tx.to_witness_payload.size).to eq(payloads[3].size)
132
+ expect(tx.to_witness_payload).to eq(payloads[3])
133
+ end
134
+ end
135
+
136
+ it '#to_hash' do
137
+ tx = Bitcoin::Protocol::Tx.new(payloads[0])
138
+ expect(tx.to_hash.keys)
139
+ .to eq(%w[hash ver vin_sz vout_sz lock_time size in out])
140
+
141
+ # witness tx
142
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
143
+ expect(tx.to_hash.keys)
144
+ .to eq(%w[hash ver vin_sz vout_sz lock_time size in out])
145
+ end
146
+
147
+ it '.from_hash' do
148
+ orig_tx = Bitcoin::Protocol::Tx.new(payloads[0])
149
+ tx = Bitcoin::Protocol::Tx.from_hash(orig_tx.to_hash)
150
+ expect(tx.payload).to eq(payloads[0])
151
+ expect(tx.to_payload.size).to eq(payloads[0].size)
152
+ expect(tx.to_payload).to eq(payloads[0])
153
+ expect(tx.to_hash).to eq(orig_tx.to_hash)
154
+ expect(Bitcoin::Protocol::Tx.binary_from_hash(orig_tx.to_hash))
155
+ .to eq(payloads[0])
156
+
157
+ h = orig_tx.to_hash.merge('ver' => 123)
158
+ expect do
159
+ Bitcoin::Protocol::Tx.from_hash(h)
160
+ end.to raise_error(Exception,
161
+ 'Tx hash mismatch! Claimed: ' \
162
+ '6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb2' \
163
+ '8e59f2d02b4, Actual: 395cd28c334ac84ed125ec5ccd5bc29ea' \
164
+ 'dcc96b79c337d0a87a19df64ea3b548')
165
+
166
+ # witness tx(P2WPKH)
167
+ orig_tx = Bitcoin::Protocol::Tx.new(payloads[3])
168
+ tx = Bitcoin::Protocol::Tx.from_hash(orig_tx.to_hash)
169
+ expect(tx.payload).to eq(payloads[3])
170
+ expect(tx.to_witness_payload.size).to eq(payloads[3].size)
171
+ expect(tx.to_witness_payload).to eq(payloads[3])
172
+ expect(tx.to_hash).to eq(orig_tx.to_hash)
173
+ end
174
+
175
+ it '.binary_from_hash' do
176
+ orig_tx = Bitcoin::Protocol::Tx.new(payloads[0])
177
+ expect(Bitcoin::Protocol::Tx.binary_from_hash(orig_tx.to_hash).size).to eq(payloads[0].size)
178
+ expect(Bitcoin::Protocol::Tx.binary_from_hash(orig_tx.to_hash)).to eq(payloads[0])
179
+
180
+ orig_tx = Bitcoin::Protocol::Tx.new(payloads[3])
181
+ expect(Bitcoin::Protocol::Tx.binary_from_hash(orig_tx.to_hash).size).to eq(payloads[3].size)
182
+ expect(Bitcoin::Protocol::Tx.binary_from_hash(orig_tx.to_hash)).to eq(payloads[3])
183
+ end
184
+
185
+ it '#to_json' do
186
+ tx = Bitcoin::Protocol::Tx.new(payloads[0])
187
+ expect(tx.to_json).to eq(json[0])
188
+
189
+ tx = Bitcoin::Protocol::Tx.new(payloads[1])
190
+ expect(tx.to_json).to eq(json[1])
191
+
192
+ tx = Bitcoin::Protocol::Tx.new(payloads[2])
193
+ expect(tx.to_json).to eq(json[2])
194
+
195
+ tx = Bitcoin::Protocol::Tx.new(
196
+ fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin')
197
+ )
198
+ expect(tx.to_json)
199
+ .to eq(fixtures_file(
200
+ 'rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json'
201
+ ))
202
+
203
+ tx = Bitcoin::Protocol::Tx.new(payloads[3])
204
+ expect(tx.to_json).to eq(json[3])
205
+ end
206
+
207
+ it '.from_json' do
208
+ json_string = fixtures_file(
209
+ 'rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json'
210
+ )
211
+ tx = Bitcoin::Protocol::Tx.from_json(json_string)
212
+ expect(tx.to_json).to eq(json_string)
213
+
214
+ json_string = fixtures_file(
215
+ 'rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json'
216
+ )
217
+ tx = Bitcoin::Protocol::Tx.from_json(json_string)
218
+ expect(tx.to_json).to eq(json_string)
219
+
220
+ json_string = fixtures_file(
221
+ 'rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json'
222
+ )
223
+ binary_string = fixtures_file(
224
+ 'rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin'
225
+ )
226
+ tx = Bitcoin::Protocol::Tx.from_json(json_string)
227
+ expect(tx.to_payload).to eq(binary_string)
228
+ expect(tx.to_json).to eq(json_string)
229
+
230
+ tx = Bitcoin::Protocol::Tx.from_json(
231
+ fixtures_file(
232
+ 'rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json'
233
+ )
234
+ )
235
+ expect(Bitcoin::Protocol::Tx.new(tx.to_payload).to_json)
236
+ .to eq(tx.to_json)
237
+ expect(tx.hash)
238
+ .to eq('ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5')
239
+
240
+ # coinbase tx with non-default sequence
241
+ json_string = fixtures_file(
242
+ '0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json'
243
+ )
244
+ tx = Bitcoin::Protocol::Tx.from_json(json_string)
245
+ expect(Bitcoin::Protocol::Tx.new(tx.to_payload).to_json).to eq(json_string)
246
+
247
+ # TODO: Deprecate this since Toshi is no longer maintained?
248
+ # toshi format
249
+ expect(
250
+ Bitcoin::Protocol::Tx.from_json(
251
+ fixtures_file('rawtx-02-toshi.json')
252
+ ).to_payload
253
+ ).to eq(
254
+ Bitcoin::Protocol::Tx.from_json(fixtures_file('rawtx-02.json')).to_payload
255
+ )
256
+ expect(
257
+ Bitcoin::Protocol::Tx.from_json(
258
+ fixtures_file('rawtx-03-toshi.json')
259
+ ).to_payload
260
+ ).to eq(
261
+ Bitcoin::Protocol::Tx.from_json(fixtures_file('rawtx-03.json')).to_payload
262
+ )
263
+ expect(
264
+ Bitcoin::Protocol::Tx.from_json(
265
+ fixtures_file('coinbase-toshi.json')
266
+ ).to_payload
267
+ ).to eq(
268
+ Bitcoin::Protocol::Tx.from_json(fixtures_file('coinbase.json')).to_payload
269
+ )
270
+
271
+ # witness tx
272
+ json_string = fixtures_file('rawtx-p2wpkh.json')
273
+ tx = Bitcoin::Protocol::Tx.from_json(json_string)
274
+ expect(tx.to_witness_payload).to eq(payloads[3])
275
+ expect(tx.to_json).to eq(json_string)
276
+ end
277
+
278
+ it '.binary_from_json' do
279
+ json_string = fixtures_file(
280
+ 'rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json'
281
+ )
282
+ binary_string = fixtures_file(
283
+ 'rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin'
284
+ )
285
+ expect(Bitcoin::Protocol::Tx.binary_from_json(json_string))
286
+ .to eq(binary_string)
287
+ end
288
+
289
+ describe '.compare_big_endian' do
290
+ it 'compares arrays of bytes' do
291
+ # This function is used in validating an ECDSA signature's S value
292
+ c1 = []
293
+ c2 = []
294
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(0)
295
+
296
+ c1 = [0]
297
+ c2 = []
298
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(0)
299
+
300
+ c1 = []
301
+ c2 = [0]
302
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(0)
303
+
304
+ c1 = [5]
305
+ c2 = [5]
306
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(0)
307
+
308
+ c1 = [4]
309
+ c2 = [5]
310
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(-1)
311
+
312
+ c1 = [4]
313
+ c2 = [5]
314
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(-1)
315
+
316
+ c1 = [5]
317
+ c2 = [4]
318
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(1)
319
+
320
+ c1 = [5]
321
+ c2 = [4]
322
+ expect(Bitcoin::Script.compare_big_endian(c1, c2)).to eq(1)
323
+ end
324
+ end
325
+
326
+ describe '.is_der_signature?' do
327
+ it 'validates ECDSA signature format' do
328
+ # TX 3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae
329
+ sig_orig = [
330
+ '304502210088984573e3e4f33db7df6aea313f1ce67a3ef3532ea89991494c7f0182' \
331
+ '58371802206ceefc9291450dbd40d834f249658e0f64662d52a41cf14e20c9781144' \
332
+ 'f2fe0701'
333
+ ].pack('H*')
334
+ expect(Bitcoin::Script.is_der_signature?(sig_orig)).to be true
335
+ expect(Bitcoin::Script.is_defined_hashtype_signature?(sig_orig)).to be true
336
+
337
+ # Trimmed to be too short
338
+ sig = sig_orig.slice(0, 8)
339
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
340
+
341
+ # Zero-padded to be too long
342
+ sig = String.new(sig_orig)
343
+ sig << 0x00
344
+ sig << 0x00
345
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
346
+
347
+ # Wrong first byte
348
+ sig_bytes = sig_orig.unpack('C*')
349
+ sig_bytes[0] = 0x20
350
+ sig = sig_bytes.pack('C*')
351
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
352
+
353
+ # Length byte broken
354
+ sig_bytes = sig_orig.unpack('C*')
355
+ sig_bytes[1] = 0x20
356
+ sig = sig_bytes.pack('C*')
357
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
358
+
359
+ # Incorrect R value type
360
+ sig_bytes = sig_orig.unpack('C*')
361
+ sig_bytes[2] = 0x03
362
+ sig = sig_bytes.pack('C*')
363
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
364
+
365
+ # R value length infeasibly long
366
+ sig_bytes = sig_orig.unpack('C*')
367
+ sig_bytes[3] = sig_orig.size - 4
368
+ sig = sig_bytes.pack('C*')
369
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
370
+
371
+ # Negative R value
372
+ sig_bytes = sig_orig.unpack('C*')
373
+ sig_bytes[4] = 0x80 | sig_bytes[4]
374
+ sig = sig_bytes.pack('C*')
375
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
376
+
377
+ # R value excessively padded
378
+ sig_bytes = sig_orig.unpack('C*')
379
+ sig_bytes[5] = 0x00
380
+ sig = sig_bytes.pack('C*')
381
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
382
+
383
+ # Incorrect S value type
384
+ sig_bytes = sig_orig.unpack('C*')
385
+ sig_bytes[37] = 0x03
386
+ sig = sig_bytes.pack('C*')
387
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
388
+
389
+ # Zero S length
390
+ sig_bytes = sig_orig.unpack('C*')
391
+ sig_bytes[38] = 0x00
392
+ sig = sig_bytes.pack('C*')
393
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
394
+
395
+ # Negative S value
396
+ sig_bytes = sig_orig.unpack('C*')
397
+ sig_bytes[39] = 0x80 | sig_bytes[39]
398
+ sig = sig_bytes.pack('C*')
399
+ expect(Bitcoin::Script.is_der_signature?(sig)).to be false
400
+ end
401
+ end
402
+
403
+ it '#verify_input_signature' do
404
+ # transaction-2 of block-170
405
+ tx = Bitcoin::Protocol::Tx.new(
406
+ fixtures_file(
407
+ 'rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin'
408
+ )
409
+ )
410
+ expect(tx.hash)
411
+ .to eq('f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16')
412
+
413
+ # transaction-1 (coinbase) of block-9
414
+ outpoint_tx = Bitcoin::Protocol::Tx.new(
415
+ fixtures_file(
416
+ 'rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin'
417
+ )
418
+ )
419
+ expect(outpoint_tx.hash)
420
+ .to eq('0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9')
421
+
422
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
423
+
424
+ # Only one test where we provide the TxOut is needed since when providing
425
+ # the full outpoint_tx the verification logic doesn't change.
426
+ expect(tx.verify_input_signature(0, outpoint_tx.out[0])).to be true
427
+
428
+ tx = Bitcoin::Protocol::Tx.from_json(
429
+ fixtures_file(
430
+ 'rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json'
431
+ )
432
+ )
433
+ expect(tx.hash)
434
+ .to eq('c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73')
435
+
436
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
437
+ fixtures_file(
438
+ 'rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json'
439
+ )
440
+ )
441
+ expect(outpoint_tx.hash)
442
+ .to eq('406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602')
443
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
444
+
445
+ tx = Bitcoin::Protocol::Tx.from_json(
446
+ fixtures_file(
447
+ '0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json'
448
+ )
449
+ )
450
+ expect(tx.hash)
451
+ .to eq('0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae')
452
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
453
+ fixtures_file(
454
+ 'aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json'
455
+ )
456
+ )
457
+ expect(outpoint_tx.hash)
458
+ .to eq('aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4')
459
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
460
+
461
+ # SIGHASH_ANYONECANPAY transaction
462
+ tx = Bitcoin::Protocol::Tx.from_json(
463
+ fixtures_file(
464
+ '51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json'
465
+ )
466
+ )
467
+ expect(tx.hash)
468
+ .to eq('51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e')
469
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
470
+ fixtures_file(
471
+ '761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json'
472
+ )
473
+ )
474
+ expect(outpoint_tx.hash)
475
+ .to eq('761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6')
476
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
477
+
478
+ # BIP12/OP_EVAL does't exist.
479
+ tx = Bitcoin::Protocol::Tx.from_json(
480
+ fixtures_file(
481
+ '03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json'
482
+ )
483
+ )
484
+ expect(tx.hash)
485
+ .to eq('03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99')
486
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
487
+ fixtures_file(
488
+ 'f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json'
489
+ )
490
+ )
491
+ expect(outpoint_tx.hash)
492
+ .to eq('f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b')
493
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
494
+
495
+ # (SIGHASH_ANYONECANPAY | SIGHASH_SINGLE) p2sh transaction
496
+ tx = Bitcoin::Protocol::Tx.from_json(
497
+ fixtures_file(
498
+ '7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json'
499
+ )
500
+ )
501
+ expect(tx.hash)
502
+ .to eq('7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d')
503
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
504
+ fixtures_file(
505
+ '3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json'
506
+ )
507
+ )
508
+ expect(outpoint_tx.hash)
509
+ .to eq('3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477')
510
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
511
+
512
+ # SIGHHASH_SINGLE - https://bitcointalk.org/index.php?topic=260595.0
513
+ tx = Bitcoin::Protocol::Tx.from_json(
514
+ fixtures_file(
515
+ '315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json'
516
+ )
517
+ )
518
+ expect(tx.hash)
519
+ .to eq('315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f')
520
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
521
+ fixtures_file(
522
+ '69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json'
523
+ )
524
+ )
525
+ expect(outpoint_tx.hash)
526
+ .to eq('69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc')
527
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
528
+ expect(tx.verify_input_signature(1, outpoint_tx)).to be true
529
+
530
+ # 0:1:01 <signature> 0:1:01 0:1:00 <pubkey> OP_SWAP OP_1ADD OP_CHECKMULTISIG
531
+ tx = Bitcoin::Protocol::Tx.from_json(
532
+ fixtures_file(
533
+ 'cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json'
534
+ )
535
+ )
536
+ expect(tx.hash)
537
+ .to eq('cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2')
538
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
539
+ fixtures_file(
540
+ '514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json'
541
+ )
542
+ )
543
+ expect(outpoint_tx.hash)
544
+ .to eq('514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58')
545
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
546
+
547
+ # OP_CHECKSIG with OP_0 from mainnet
548
+ # a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954 output 0
549
+ tx = Bitcoin::Protocol::Tx.from_json(
550
+ fixtures_file(
551
+ 'tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json'
552
+ )
553
+ )
554
+ expect(tx.hash)
555
+ .to eq('9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28')
556
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
557
+ fixtures_file(
558
+ 'tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json'
559
+ )
560
+ )
561
+ expect(outpoint_tx.hash)
562
+ .to eq('a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954')
563
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
564
+
565
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
566
+ tx = Bitcoin::Protocol::Tx.from_json(
567
+ fixtures_file(
568
+ 'tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json'
569
+ )
570
+ )
571
+ expect(tx.hash)
572
+ .to eq('46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa')
573
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
574
+ fixtures_file(
575
+ 'tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json'
576
+ )
577
+ )
578
+ expect(outpoint_tx.hash)
579
+ .to eq('bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224')
580
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
581
+
582
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
583
+ tx = Bitcoin::Protocol::Tx.from_json(
584
+ fixtures_file(
585
+ 'tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json'
586
+ )
587
+ )
588
+ expect(tx.hash)
589
+ .to eq('aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8')
590
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
591
+ fixtures_file(
592
+ 'tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json'
593
+ )
594
+ )
595
+ expect(outpoint_tx.hash)
596
+ .to eq('326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e')
597
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
598
+
599
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input
600
+ tx = Bitcoin::Protocol::Tx.from_json(
601
+ fixtures_file(
602
+ 'tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json'
603
+ )
604
+ )
605
+ expect(tx.hash)
606
+ .to eq('6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190')
607
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
608
+ fixtures_file(
609
+ 'tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json'
610
+ )
611
+ )
612
+ expect(outpoint_tx.hash)
613
+ .to eq('a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944')
614
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
615
+
616
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input
617
+ # when used in ScriptSig
618
+ tx = Bitcoin::Protocol::Tx.from_json(
619
+ fixtures_file(
620
+ 'tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json'
621
+ )
622
+ )
623
+ expect(tx.hash)
624
+ .to eq('eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb')
625
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
626
+ fixtures_file(
627
+ 'tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json'
628
+ )
629
+ )
630
+ expect(outpoint_tx.hash)
631
+ .to eq('b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d')
632
+ expect(tx.verify_input_signature(1, outpoint_tx)).to be true
633
+
634
+ # OP_DUP OP_HASH160
635
+ tx = Bitcoin::Protocol::Tx.from_json(
636
+ fixtures_file(
637
+ 'tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json'
638
+ )
639
+ )
640
+ expect(tx.hash)
641
+ .to eq('5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f')
642
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
643
+ fixtures_file(
644
+ 'tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json'
645
+ )
646
+ )
647
+ expect(outpoint_tx.hash)
648
+ .to eq('b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9')
649
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
650
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
651
+ fixtures_file(
652
+ 'tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json'
653
+ )
654
+ )
655
+ expect(outpoint_tx.hash)
656
+ .to eq('ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742')
657
+ expect(tx.verify_input_signature(1, outpoint_tx)).to be true
658
+
659
+ # testnet3 e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009
660
+ tx = Bitcoin::Protocol::Tx.from_json(
661
+ fixtures_file(
662
+ 'tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json'
663
+ )
664
+ )
665
+ expect(tx.hash)
666
+ .to eq('e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009')
667
+ prev_txs = {}
668
+
669
+ tx.in.map(&:previous_output).uniq.each do |i|
670
+ prev_txs[i] = Bitcoin::Protocol::Tx.from_json(
671
+ fixtures_file("tx-#{i}.json")
672
+ )
673
+ end
674
+
675
+ tx.in.each.with_index do |i, idx|
676
+ expect(
677
+ tx.verify_input_signature(idx, prev_txs[i.previous_output])
678
+ ).to be true
679
+ end
680
+
681
+ # BIP62 rule #2 - spend transaction has operations in its signature
682
+ tx = Bitcoin::Protocol::Tx.new(
683
+ fixtures_file(
684
+ 'rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin'
685
+ )
686
+ )
687
+ expect(tx.hash)
688
+ .to eq('3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e')
689
+ outpoint_tx = Bitcoin::Protocol::Tx.new(
690
+ fixtures_file(
691
+ 'rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin'
692
+ )
693
+ )
694
+ expect(outpoint_tx.hash)
695
+ .to eq('04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4')
696
+ expect(
697
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i)
698
+ ).to be true
699
+ expect(
700
+ tx.verify_input_signature(
701
+ 0, outpoint_tx, Time.now.to_i, verify_sigpushonly: true
702
+ )
703
+ ).to be false
704
+
705
+ # BIP62 rule #6 - spend transaction has an unused "0" on the signature stack
706
+ tx = Bitcoin::Protocol::Tx.new(
707
+ fixtures_file(
708
+ 'rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin'
709
+ )
710
+ )
711
+ expect(tx.hash)
712
+ .to eq('0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f')
713
+ outpoint_tx = Bitcoin::Protocol::Tx.new(
714
+ fixtures_file(
715
+ 'rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin'
716
+ )
717
+ )
718
+ expect(outpoint_tx.hash)
719
+ .to eq('f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5')
720
+ expect(
721
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i)
722
+ ).to be true
723
+ expect(
724
+ tx.verify_input_signature(
725
+ 0, outpoint_tx, Time.now.to_i, verify_cleanstack: true
726
+ )
727
+ ).to be false
728
+
729
+ # Ensure BIP62 is applied to P2SH scripts
730
+ tx = Bitcoin::Protocol::Tx.from_json(
731
+ fixtures_file(
732
+ '7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json'
733
+ )
734
+ )
735
+ expect(tx.hash)
736
+ .to eq('7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d')
737
+
738
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
739
+ fixtures_file(
740
+ '3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json'
741
+ )
742
+ )
743
+ expect(outpoint_tx.hash)
744
+ .to eq('3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477')
745
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
746
+ expect(
747
+ tx.verify_input_signature(
748
+ 0, outpoint_tx, Time.now.to_i, verify_low_s: true
749
+ )
750
+ ).to be false
751
+
752
+ # testnet3 P2SH check
753
+ tx = Bitcoin::Protocol::Tx.from_json(
754
+ fixtures_file(
755
+ '156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json'
756
+ )
757
+ )
758
+ expect(tx.hash)
759
+ .to eq('156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a')
760
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(
761
+ fixtures_file(
762
+ '8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json'
763
+ )
764
+ )
765
+ expect(outpoint_tx.hash)
766
+ .to eq('8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c')
767
+ expect(tx.verify_input_signature(0, outpoint_tx)).to be true
768
+ end
769
+
770
+ it '#verify_witness_input_signature' do
771
+ # P2WPKH
772
+ tx = Bitcoin::Protocol::Tx.new(
773
+ '01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4' \
774
+ 'e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3beb' \
775
+ 'f337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede9' \
776
+ '44ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b' \
777
+ '309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a914' \
778
+ '8280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143b' \
779
+ 'de42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7' \
780
+ 'd30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c45183315' \
781
+ '61406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368d' \
782
+ 'a1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000'.htb
783
+ )
784
+ expect(
785
+ tx.verify_witness_input_signature(
786
+ 1, '00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'.htb, 600_000_000
787
+ )
788
+ ).to be true
789
+
790
+ # P2WSH
791
+ tx = Bitcoin::Protocol::Tx.new(
792
+ '01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b' \
793
+ '9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6' \
794
+ 'c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367' \
795
+ '096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac' \
796
+ '6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a3' \
797
+ '0741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf452778' \
798
+ '9bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd3471' \
799
+ '71cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b' \
800
+ '740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6' \
801
+ 'a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749ad' \
802
+ 'c2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626a' \
803
+ 'ebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000'.htb
804
+ )
805
+ expect(
806
+ tx.verify_witness_input_signature(
807
+ 1,
808
+ '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'.htb,
809
+ 4_900_000_000
810
+ )
811
+ ).to be true
812
+
813
+ # P2SH-P2WPKH
814
+ tx = Bitcoin::Protocol::Tx.new(
815
+ '01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3c' \
816
+ 'eb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffff' \
817
+ 'ff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388' \
818
+ 'ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac' \
819
+ '02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d1' \
820
+ '2d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe' \
821
+ '9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2' \
822
+ '687392040000'.htb
823
+ )
824
+ expect(
825
+ tx.verify_witness_input_signature(
826
+ 0,
827
+ 'a9144733f37cf4db86fbc2efed2500b4f4e49f31202387'.htb,
828
+ 1_000_000_000
829
+ )
830
+ ).to be true
831
+
832
+ # P2SH-P2WSH
833
+ tx = Bitcoin::Protocol::Tx.new(
834
+ '0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca2' \
835
+ '9787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1b' \
836
+ 'b8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc' \
837
+ '0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e' \
838
+ '6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52e' \
839
+ 'eb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e' \
840
+ '4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009' \
841
+ 'a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62' \
842
+ 'e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfe' \
843
+ 'c54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a8913' \
844
+ '9c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b' \
845
+ '79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265' \
846
+ 'f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553b' \
847
+ 'a89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5' \
848
+ 'd4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1' \
849
+ '482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a' \
850
+ '34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae' \
851
+ '49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28' \
852
+ 'bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703' \
853
+ '413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb8' \
854
+ '33092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94b' \
855
+ 'a04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2' \
856
+ 'f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000'.htb
857
+ )
858
+ expect(
859
+ tx.verify_witness_input_signature(
860
+ 0, 'a9149993a429037b5d912407a71c252019287b8d27a587'.htb, 987_654_321
861
+ )
862
+ ).to be true
863
+ end
864
+
865
+ describe '#signature_hash_for_input' do
866
+ it 'sighash_all' do
867
+ prev_tx = Bitcoin::Protocol::Tx.new(
868
+ fixtures_file(
869
+ 'rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin'
870
+ )
871
+ )
872
+ expect(prev_tx.hash)
873
+ .to eq('2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a')
874
+
875
+ pubkey =
876
+ '04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa155' \
877
+ '2e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3'
878
+ key = Bitcoin.open_key(
879
+ '56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc',
880
+ pubkey
881
+ )
882
+ new_tx = Bitcoin::Protocol::Tx.new(nil)
883
+ new_tx.add_in(Bitcoin::Protocol::TxIn.new(prev_tx.binary_hash, 0, 0))
884
+ new_tx.add_out(
885
+ Bitcoin::Protocol::TxOut.value_to_address(
886
+ 1_000_000,
887
+ '1BVJWLTCtjA8wRivvrCiwjNdL6KjdMUCTZ'
888
+ )
889
+ )
890
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
891
+ sig = Bitcoin.sign_data(key, signature_hash)
892
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(
893
+ sig, [pubkey].pack('H*')
894
+ )
895
+
896
+ new_tx = Bitcoin::Protocol::Tx.new(new_tx.to_payload)
897
+ expect(new_tx.hash).not_to be_nil
898
+ expect(new_tx.verify_input_signature(0, prev_tx)).to be true
899
+
900
+ prev_tx = Bitcoin::Protocol::Tx.new(
901
+ fixtures_file(
902
+ 'rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin'
903
+ )
904
+ )
905
+ expect(prev_tx.hash)
906
+ .to eq('14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984')
907
+
908
+ pubkey =
909
+ '0409d103127d26ce93ee41f1b9b1ed4c1c243acf48e31eb5c4d88ad0342ccc010a1a' \
910
+ '8d838846cf7337f2b44bc73986c0a3cb0568fa93d068b2c8296ce8d47b1545'
911
+ key = Bitcoin.open_key(
912
+ '115ceda6c1e02d41ce65c35a30e82fb325fe3f815898a09e1a5d28bb1cc92c6e',
913
+ pubkey
914
+ )
915
+ new_tx = Bitcoin::Protocol::Tx.new(nil)
916
+ new_tx.add_in(Bitcoin::Protocol::TxIn.new(prev_tx.binary_hash, 0, 0))
917
+ pk_script = Bitcoin::Script.to_address_script(
918
+ '1FEYAh1x5jeKQMPPuv3bKnKvbgVAqXvqjW'
919
+ )
920
+ new_tx.add_out(
921
+ Bitcoin::Protocol::TxOut.new(1_000_000, pk_script)
922
+ )
923
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
924
+ sig = Bitcoin.sign_data(key, signature_hash)
925
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(
926
+ sig, [pubkey].pack('H*')
927
+ )
928
+
929
+ new_tx = Bitcoin::Protocol::Tx.new(new_tx.to_payload)
930
+ expect(new_tx.hash).not_to be_nil
931
+ expect(new_tx.verify_input_signature(0, prev_tx)).to be true
932
+
933
+ prev_tx = Bitcoin::Protocol::Tx.new(
934
+ fixtures_file(
935
+ 'rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin'
936
+ )
937
+ )
938
+ expect(prev_tx.hash)
939
+ .to eq('b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d')
940
+
941
+ pubkey = '04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef03' \
942
+ '0eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc' \
943
+ '3a52caf3'
944
+ key = Bitcoin.open_key(
945
+ '56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc',
946
+ pubkey
947
+ )
948
+ new_tx = Bitcoin::Protocol::Tx.new(nil)
949
+ new_tx.add_in(
950
+ Bitcoin::Protocol::TxIn.new(prev_tx.binary_hash, 0, 0)
951
+ )
952
+ new_tx.add_out(
953
+ Bitcoin::Protocol::TxOut.value_to_address(
954
+ 1_000_000, '14yz7fob6Q16hZu4nXfmv1kRJpSYaFtet5'
955
+ )
956
+ )
957
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
958
+ sig = Bitcoin.sign_data(key, signature_hash)
959
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(
960
+ sig, [pubkey].pack('H*')
961
+ )
962
+
963
+ new_tx = Bitcoin::Protocol::Tx.new(new_tx.to_payload)
964
+ expect(new_tx.hash).not_to be_nil
965
+ expect(new_tx.verify_input_signature(0, prev_tx)).to be true
966
+ end
967
+
968
+ it 'sighash JSON tests' do
969
+ test_cases = JSON.parse(fixtures_file('sighash.json'))
970
+
971
+ test_cases.each do |test_case|
972
+ # Single element arrays in tests are comments.
973
+ next if test_case.length == 1
974
+
975
+ transaction = Bitcoin::Protocol::Tx.new(test_case[0].htb)
976
+ subscript = test_case[1].htb
977
+ input_index = test_case[2].to_i
978
+ hash_type = test_case[3]
979
+ amount = 0
980
+ expected_sighash = test_case[4].htb_reverse
981
+
982
+ actual_sighash = transaction.signature_hash_for_input(
983
+ input_index, subscript, hash_type, amount, 0
984
+ )
985
+ expect(actual_sighash).to eq(expected_sighash)
986
+ end
987
+ end
988
+ end
989
+
990
+ it '#signature_hash_for_witness_input' do
991
+ # P2WPKH
992
+ # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#Native_P2WPKH
993
+ tx = Bitcoin::Protocol::Tx.new(
994
+ '0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad' \
995
+ '969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9' \
996
+ 'b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df3' \
997
+ '78db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e' \
998
+ '4dbe6a21b2d50ce2f0167faa815988ac11000000'.htb
999
+ )
1000
+ signature_hash = tx.signature_hash_for_witness_input(
1001
+ 1, '00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'.htb, 600_000_000
1002
+ )
1003
+ expect(signature_hash.bth)
1004
+ .to eq('c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')
1005
+
1006
+ # P2WSH
1007
+ # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#Native_P2WSH
1008
+ tx = Bitcoin::Protocol::Tx.new(
1009
+ '0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216' \
1010
+ 'b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47' \
1011
+ 'c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f814' \
1012
+ '5e5acadf23f751864167f32e0963f788ac00000000'.htb
1013
+ )
1014
+ script_pubkey =
1015
+ '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'
1016
+ witness_script =
1017
+ '21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aead' \
1018
+ 'ab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac'
1019
+ signature_hash = tx.signature_hash_for_witness_input(
1020
+ 1, script_pubkey.htb, 4_900_000_000,
1021
+ witness_script.htb, Bitcoin::Protocol::Tx::SIGHASH_TYPE[:single]
1022
+ )
1023
+ expect(signature_hash.bth)
1024
+ .to eq('82dde6e4f1e94d02c2b7ad03d2115d691f48d064e9d52f58194a6637e4194391')
1025
+
1026
+ # P2WSH with invalid witness script
1027
+ tx = Bitcoin::Protocol::Tx.new(
1028
+ '0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b921' \
1029
+ '6b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da' \
1030
+ '47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f' \
1031
+ '8145e5acadf23f751864167f32e0963f788ac00000000'.htb
1032
+ )
1033
+ script_pubkey =
1034
+ '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'
1035
+ witness_script = 'AAA'
1036
+ expect do
1037
+ tx.signature_hash_for_witness_input(
1038
+ 1, script_pubkey.htb, 4_900_000_000, witness_script.htb
1039
+ )
1040
+ end.to raise_error(
1041
+ RuntimeError, 'witness script does not match script pubkey'
1042
+ )
1043
+ end
1044
+
1045
+ it '#legacy_sigops_count' do
1046
+ expect(Bitcoin::Protocol::Tx.new(payloads[0]).legacy_sigops_count).to eq(2)
1047
+ expect(Bitcoin::Protocol::Tx.new(payloads[1]).legacy_sigops_count).to eq(2)
1048
+ expect(Bitcoin::Protocol::Tx.new(payloads[2]).legacy_sigops_count).to eq(2)
1049
+
1050
+ # Test sig ops count in inputs too.
1051
+ tx = Bitcoin::Protocol::Tx.new
1052
+ txin = Bitcoin::Protocol::TxIn.new
1053
+ txin.script_sig = Bitcoin::Script.from_string(
1054
+ '10 OP_CHECKMULTISIGVERIFY OP_CHECKSIGVERIFY'
1055
+ ).to_binary
1056
+ tx.add_in(txin)
1057
+ txout = Bitcoin::Protocol::TxOut.new
1058
+ txout.pk_script = Bitcoin::Script.from_string(
1059
+ '5 OP_CHECKMULTISIG OP_CHECKSIG'
1060
+ ).to_binary
1061
+ tx.add_out(txout)
1062
+
1063
+ expect(tx.legacy_sigops_count).to eq(20 + 1 + 20 + 1)
1064
+ end
1065
+
1066
+ describe 'Tx - final?' do
1067
+ it 'should be final if lock_time == 0' do
1068
+ tx = Bitcoin::Protocol::Tx.new
1069
+ tx.lock_time = 0
1070
+ expect(tx.final?(0, 0)).to be true
1071
+
1072
+ # even if has non-final input:
1073
+ txin = Bitcoin::Protocol::TxIn.new
1074
+ txin.sequence = "\x01\x00\x00\x00"
1075
+ tx.add_in(txin)
1076
+ expect(tx.final?(0, 0)).to be true
1077
+ end
1078
+
1079
+ it 'should be final if lock_time is below block_height' do
1080
+ tx = Bitcoin::Protocol::Tx.new
1081
+ txin = Bitcoin::Protocol::TxIn.new
1082
+ txin.sequence = "\x01\x00\x00\x00"
1083
+ tx.add_in(txin)
1084
+ tx.lock_time = 6543
1085
+
1086
+ expect(tx.final?(6000, 0)).to be false
1087
+ # when equal to block height, still not final
1088
+ expect(tx.final?(6543, 0)).to be false
1089
+ expect(tx.final?(6544, 0)).to be true
1090
+ expect(tx.final?(9999, 0)).to be true
1091
+ end
1092
+
1093
+ it 'should be final if lock_time is below timestamp' do
1094
+ tx = Bitcoin::Protocol::Tx.new
1095
+ txin = Bitcoin::Protocol::TxIn.new
1096
+ txin.sequence = "\xff\xff\xff\xff"
1097
+ tx.add_in(txin)
1098
+ txin = Bitcoin::Protocol::TxIn.new
1099
+ txin.sequence = "\x01\x00\x00\x00"
1100
+ tx.add_in(txin)
1101
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD # when equal, interpreted as threshold
1102
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD - 1)).to be false
1103
+ # when equal to timestamp, still not final
1104
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD)).to be false
1105
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 1)).to be true
1106
+
1107
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
1108
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 1)).to be false
1109
+ # when equal to timestamp, still not final
1110
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 666)).to be false
1111
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 667)).to be true
1112
+ end
1113
+
1114
+ it 'should be final if all inputs are finalized regardless of lock_time' do
1115
+ tx = Bitcoin::Protocol::Tx.new
1116
+ txin = Bitcoin::Protocol::TxIn.new
1117
+ txin.sequence = "\xff\xff\xff\xff"
1118
+ tx.add_in(txin)
1119
+ txin = Bitcoin::Protocol::TxIn.new
1120
+ txin.sequence = "\xff\xff\xff\xff"
1121
+ tx.add_in(txin)
1122
+
1123
+ tx.lock_time = 6543
1124
+ expect(tx.final?(6000, 0)).to be true
1125
+ expect(tx.final?(6543, 0)).to be true
1126
+ expect(tx.final?(6544, 0)).to be true
1127
+ expect(tx.final?(9999, 0)).to be true
1128
+
1129
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD
1130
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD - 1)).to be true
1131
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD)).to be true
1132
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 1)).to be true
1133
+
1134
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
1135
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 1)).to be true
1136
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 666)).to be true
1137
+ expect(tx.final?(0, Bitcoin::LOCKTIME_THRESHOLD + 667)).to be true
1138
+ end
1139
+ end
1140
+
1141
+ it '#calculate_minimum_fee' do
1142
+ tx = Bitcoin::Protocol::Tx.new(
1143
+ fixtures_file(
1144
+ 'rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin'
1145
+ )
1146
+ )
1147
+ expect(tx.minimum_relay_fee).to eq(0)
1148
+ expect(tx.minimum_block_fee).to eq(0)
1149
+ tx = Bitcoin::Protocol::Tx.from_json(
1150
+ fixtures_file(
1151
+ 'bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json'
1152
+ )
1153
+ )
1154
+ expect(tx.minimum_relay_fee).to eq(0)
1155
+ expect(tx.minimum_block_fee).to eq(10_000)
1156
+ end
1157
+
1158
+ it '#calculate_minimum_fee for litecoin' do
1159
+ tx = Bitcoin::Protocol::Tx.from_json(
1160
+ fixtures_file(
1161
+ 'litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json'
1162
+ )
1163
+ )
1164
+ expect(tx.minimum_relay_fee).to eq(0)
1165
+ expect(tx.minimum_block_fee).to eq(30_000)
1166
+
1167
+ Bitcoin.network = :litecoin # change to litecoin
1168
+ expect(tx.minimum_relay_fee).to eq(0)
1169
+ expect(tx.minimum_block_fee).to eq(100_000)
1170
+ end
1171
+
1172
+ it 'should compare transactions' do
1173
+ tx1 = Bitcoin::Protocol::Tx.new(payloads[0])
1174
+ tx2 = Bitcoin::Protocol::Tx.new(payloads[1])
1175
+
1176
+ expect(Bitcoin::Protocol::Tx.from_json(tx1.to_json)).to eq(tx1)
1177
+ expect(tx1).not_to eq(tx2)
1178
+ expect(tx1).not_to be_nil
1179
+ end
1180
+
1181
+ describe 'Tx - BIP Scripts' do
1182
+ it 'should do OP_CHECKMULTISIG' do
1183
+ # checkmultisig without checkhashverify
1184
+ tx = Bitcoin::Protocol::Tx.from_json(
1185
+ fixtures_file(
1186
+ '23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json'
1187
+ )
1188
+ )
1189
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1190
+ fixtures_file(
1191
+ '60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json'
1192
+ )
1193
+ )
1194
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1195
+
1196
+ # p2sh + multisig transaction from mainnet
1197
+ tx = Bitcoin::Protocol::Tx.from_json(
1198
+ fixtures_file(
1199
+ 'rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json'
1200
+ )
1201
+ )
1202
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1203
+ fixtures_file(
1204
+ 'rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json'
1205
+ )
1206
+ )
1207
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1208
+
1209
+ # checkmultisig for testnet3 tx:
1210
+ # 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1 input
1211
+ # index 1
1212
+ tx = Bitcoin::Protocol::Tx.from_json(
1213
+ fixtures_file(
1214
+ 'tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json'
1215
+ )
1216
+ )
1217
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1218
+ fixtures_file(
1219
+ 'tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json'
1220
+ )
1221
+ )
1222
+ expect(tx.verify_input_signature(1, prev_tx)).to be true
1223
+ end
1224
+
1225
+ it 'should do P2SH with inner OP_CHECKMULTISIG (BIP 0016)' do
1226
+ tx = Bitcoin::Protocol::Tx.from_json(
1227
+ fixtures_file(
1228
+ '3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json'
1229
+ )
1230
+ )
1231
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1232
+ fixtures_file(
1233
+ '35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json'
1234
+ )
1235
+ )
1236
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1237
+
1238
+ tx = Bitcoin::Protocol::Tx.from_json(
1239
+ fixtures_file(
1240
+ 'bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json'
1241
+ )
1242
+ )
1243
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1244
+ fixtures_file(
1245
+ 'ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json'
1246
+ )
1247
+ )
1248
+ expect(tx.verify_input_signature(1, prev_tx)).to be true
1249
+
1250
+ # p2sh transaction with non-standard OP_CHECKMULTISIG inside found in
1251
+ # testnet3 tx:
1252
+ # d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830
1253
+ tx = Bitcoin::Protocol::Tx.from_json(
1254
+ fixtures_file(
1255
+ 'tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json'
1256
+ )
1257
+ )
1258
+ expect(tx.hash)
1259
+ .to eq('d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830')
1260
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1261
+ fixtures_file(
1262
+ 'tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json'
1263
+ )
1264
+ )
1265
+ expect(prev_tx.hash)
1266
+ .to eq('313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0')
1267
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1268
+ end
1269
+
1270
+ it 'should do P2SH with inner OP_CHECKSIG' do
1271
+ # p2sh transaction with non-standard OP_CHECKSIG inside found in testnet3
1272
+ # tx: 3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae
1273
+ tx = Bitcoin::Protocol::Tx.from_json(
1274
+ fixtures_file(
1275
+ 'tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json'
1276
+ )
1277
+ )
1278
+ expect(tx.hash)
1279
+ .to eq('3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae')
1280
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1281
+ fixtures_file(
1282
+ 'tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json'
1283
+ )
1284
+ )
1285
+ expect(prev_tx.hash)
1286
+ .to eq('44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a')
1287
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1288
+ end
1289
+
1290
+ it 'should do OP_CHECKMULTISIG with OP_0 used as a pubkey' do
1291
+ tx = Bitcoin::Protocol::Tx.from_json(
1292
+ fixtures_file(
1293
+ 'tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json'
1294
+ )
1295
+ )
1296
+ expect(tx.hash)
1297
+ .to eq('6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba')
1298
+ prev_tx = Bitcoin::Protocol::Tx.from_json(
1299
+ fixtures_file(
1300
+ 'tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json'
1301
+ )
1302
+ )
1303
+ expect(prev_tx.hash)
1304
+ .to eq('4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9')
1305
+ expect(tx.verify_input_signature(0, prev_tx)).to be true
1306
+ end
1307
+ end
1308
+
1309
+ it 'lexicographical_sort' do
1310
+ tx = Bitcoin::Protocol::Tx.from_json(
1311
+ fixtures_file(
1312
+ 'tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json'
1313
+ )
1314
+ )
1315
+ expect(tx.hash)
1316
+ .to eq('0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3')
1317
+
1318
+ tx.lexicographical_sort!
1319
+ expect(tx.in[0].previous_output)
1320
+ .to eq('0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57')
1321
+ expect(tx.in[1].previous_output)
1322
+ .to eq('26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024')
1323
+ expect(tx.in[2].previous_output)
1324
+ .to eq('28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2')
1325
+ expect(tx.in[3].previous_output)
1326
+ .to eq('381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d')
1327
+ expect(tx.in[4].previous_output)
1328
+ .to eq('3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2')
1329
+ expect(tx.in[5].previous_output)
1330
+ .to eq('402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a')
1331
+ expect(tx.in[6].previous_output)
1332
+ .to eq('54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a')
1333
+ expect(tx.in[7].previous_output)
1334
+ .to eq('643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa')
1335
+ expect(tx.in[8].previous_output)
1336
+ .to eq('6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1')
1337
+ expect(tx.in[9].previous_output)
1338
+ .to eq('7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191')
1339
+ expect(tx.in[10].previous_output)
1340
+ .to eq('7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4')
1341
+ expect(tx.in[11].previous_output)
1342
+ .to eq('a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086')
1343
+ expect(tx.in[12].previous_output)
1344
+ .to eq('b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8')
1345
+ expect(tx.in[13].previous_output)
1346
+ .to eq('bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85')
1347
+ expect(tx.in[14].previous_output)
1348
+ .to eq('de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9')
1349
+ expect(tx.in[15].previous_output)
1350
+ .to eq('f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45')
1351
+ expect(tx.in[16].previous_output)
1352
+ .to eq('f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60')
1353
+ expect(tx.out[0].value).to eq(400_057_456)
1354
+ expect(tx.out[1].value).to eq(40_000_000_000)
1355
+
1356
+ tx = Bitcoin::Protocol::Tx.from_json(
1357
+ fixtures_file(
1358
+ 'tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json'
1359
+ )
1360
+ )
1361
+ expect(tx.hash)
1362
+ .to eq('28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f')
1363
+
1364
+ tx.lexicographical_sort!
1365
+ expect(tx.in[0].previous_output)
1366
+ .to eq('35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055')
1367
+ expect(tx.in[0].prev_out_index).to eq(0)
1368
+ expect(tx.in[1].previous_output)
1369
+ .to eq('35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055')
1370
+ expect(tx.in[1].prev_out_index).to eq(1)
1371
+ expect(tx.out[0].value).to eq(100_000_000)
1372
+ expect(tx.out[1].value).to eq(2_400_000_000)
1373
+
1374
+ tx = Bitcoin::Protocol::Tx.new
1375
+ tx.add_out(Bitcoin::Protocol::TxOut.new(500, 'bbbbbbbb'.htb))
1376
+ tx.add_out(Bitcoin::Protocol::TxOut.new(500, 'aaaaaaaa'.htb))
1377
+ tx.add_out(Bitcoin::Protocol::TxOut.new(500, 'cccccccc'.htb))
1378
+
1379
+ tx.lexicographical_sort!
1380
+ expect(tx.out[0].pk_script.bth).to eq('aaaaaaaa')
1381
+ expect(tx.out[1].pk_script.bth).to eq('bbbbbbbb')
1382
+ expect(tx.out[2].pk_script.bth).to eq('cccccccc')
1383
+ end
1384
+
1385
+ describe 'verify_input_signature' do
1386
+ # rubocop:disable Metrics/CyclomaticComplexity
1387
+ def parse_script(script_str)
1388
+ script = Bitcoin::Script.new('')
1389
+
1390
+ # Disabling the below rubocop check since the proposed fix does not work
1391
+ # on Ruby versions < 2.3. If we ever drop support for these then it can be
1392
+ # fixed
1393
+
1394
+ buf = ''.dup
1395
+
1396
+ script_str.split.each do |token|
1397
+ opcode = Bitcoin::Script::OPCODES_PARSE_STRING[token] ||
1398
+ Bitcoin::Script::OPCODES_PARSE_STRING['OP_' + token]
1399
+ if opcode
1400
+ buf << [opcode].pack('C')
1401
+ next
1402
+ end
1403
+
1404
+ data =
1405
+ case token
1406
+ when /\A-?\d+\z/
1407
+ i = token.to_i
1408
+ opcode =
1409
+ case i
1410
+ when -1 then Bitcoin::Script::OP_1NEGATE
1411
+ when 0 then Bitcoin::Script::OP_0
1412
+ when 1 then Bitcoin::Script::OP_1
1413
+ when 2..16 then Bitcoin::Script::OP_2 + i - 2
1414
+ end
1415
+
1416
+ if opcode
1417
+ [opcode].pack('C')
1418
+ else
1419
+ Bitcoin::Script.pack_pushdata(script.cast_to_string(i))
1420
+ end
1421
+ when /\A'(.*)'\z/ then
1422
+ Bitcoin::Script.pack_pushdata(Regexp.last_match(1))
1423
+ when /\A0x([0-9a-fA-F]+)\z/ then Regexp.last_match(1).htb
1424
+ else raise "Unexpected token #{token}"
1425
+ end
1426
+ buf << data
1427
+ end
1428
+ buf
1429
+ end
1430
+
1431
+ def parse_flags(flags_str)
1432
+ flags_str.split(',').each_with_object({}) do |flag_str, opts|
1433
+ case flag_str.to_sym
1434
+ when :STRICTENC then opts[:verify_strictenc] = true
1435
+ when :DERSIG then opts[:verify_dersig] = true
1436
+ when :LOW_S then opts[:verify_low_s] = true
1437
+ when :SIGPUSHONLY then opts[:verify_sigpushonly] = true
1438
+ when :MINIMALDATA then opts[:verify_minimaldata] = true
1439
+ when :CLEANSTACK then opts[:verify_cleanstack] = true
1440
+ when :SIGHASH_FORKID then opts[:fork_id] = 0
1441
+ end
1442
+ end
1443
+ end
1444
+ # rubocop:enable Metrics/CyclomaticComplexity
1445
+
1446
+ it 'script JSON tests' do
1447
+ test_cases = JSON.parse(fixtures_file('script_tests.json'))
1448
+
1449
+ test_cases.each do |test_case|
1450
+ # Single element arrays in tests are comments.
1451
+ next if test_case.length == 1
1452
+
1453
+ value =
1454
+ if test_case[0].is_a?(Array)
1455
+ (test_case.shift[0] * 10**8).to_i
1456
+ else
1457
+ 0
1458
+ end
1459
+
1460
+ # TODO: Implement these opcodes correctly
1461
+ # NOTE: Need to use `match` instead of `match?` because Ruby < 2.4 does
1462
+ # not support the latter function.
1463
+
1464
+ # rubocop:disable Performance/RedundantMatch
1465
+ if test_case[0].match(
1466
+ /CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/
1467
+ )
1468
+ next
1469
+ end
1470
+
1471
+ if test_case[1].match(
1472
+ /CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/
1473
+ )
1474
+ next
1475
+ end
1476
+ # rubocop:enable Performance/RedundantMatch
1477
+
1478
+ script_sig = parse_script(test_case[0])
1479
+ script_pubkey = parse_script(test_case[1])
1480
+ opts = parse_flags(test_case[2])
1481
+ expect_success = test_case[3] == 'OK'
1482
+
1483
+ # A lot of the test cases are failing, so for now we only test the
1484
+ # SIGHASH_FORKID ones.
1485
+ # TODO: Get this spec passing without this line.
1486
+ next unless opts[:fork_id]
1487
+
1488
+ crediting_tx = Bitcoin::Protocol::Tx.new
1489
+ crediting_tx.add_in(Bitcoin::Protocol::TxIn.new)
1490
+ crediting_tx.in[0].prev_out_hash = Bitcoin::Protocol::TxIn::NULL_HASH
1491
+ crediting_tx.in[0].prev_out_index = Bitcoin::Protocol::TxIn::COINBASE_INDEX
1492
+ crediting_tx.in[0].script_sig = parse_script('0 0')
1493
+ crediting_tx.add_out(Bitcoin::Protocol::TxOut.new)
1494
+ crediting_tx.out[0].value = value
1495
+ crediting_tx.out[0].pk_script = script_pubkey
1496
+ crediting_tx.refresh_hash
1497
+
1498
+ spending_tx = Bitcoin::Protocol::Tx.new
1499
+ spending_tx.add_in(Bitcoin::Protocol::TxIn.new)
1500
+ spending_tx.in[0].prev_out_hash = crediting_tx.binary_hash
1501
+ spending_tx.in[0].prev_out_index = 0
1502
+ spending_tx.in[0].script_sig = script_sig
1503
+ spending_tx.add_out(Bitcoin::Protocol::TxOut.new)
1504
+ spending_tx.out[0].value = value
1505
+ spending_tx.out[0].pk_script = ''
1506
+ spending_tx.refresh_hash
1507
+
1508
+ success = spending_tx.verify_input_signature(
1509
+ 0, crediting_tx, Time.now.to_i, opts
1510
+ )
1511
+ expect(success).to eq(expect_success)
1512
+ end
1513
+ end
1514
+ end
1515
+ end