bitcoin-ruby 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
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