monacoin-ruby 0.1.2

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 (195) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +5 -0
  4. data/COPYING +18 -0
  5. data/Gemfile +15 -0
  6. data/Gemfile.lock +33 -0
  7. data/README.rdoc +210 -0
  8. data/Rakefile +112 -0
  9. data/bin/monacoin_shell +12 -0
  10. data/bitcoin-ruby.gemspec +23 -0
  11. data/examples/bbe_verify_tx.rb +60 -0
  12. data/examples/concept-blockchain-pow.rb +151 -0
  13. data/examples/connect.rb +36 -0
  14. data/examples/generate_tx.rb +34 -0
  15. data/examples/simple_network_monitor_and_util.rb +195 -0
  16. data/spec/bitcoin/bitcoin_spec.rb +598 -0
  17. data/spec/bitcoin/bloom_filter_spec.rb +23 -0
  18. data/spec/bitcoin/builder_spec.rb +342 -0
  19. data/spec/bitcoin/contracthash_spec.rb +45 -0
  20. data/spec/bitcoin/dogecoin_spec.rb +176 -0
  21. data/spec/bitcoin/ext_key_spec.rb +180 -0
  22. data/spec/bitcoin/ffi_openssl.rb +45 -0
  23. data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
  24. data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
  25. data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
  26. data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
  27. data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
  28. data/spec/bitcoin/fixtures/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +23 -0
  29. data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
  30. data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
  31. data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
  32. data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
  33. data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
  34. data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
  35. data/spec/bitcoin/fixtures/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +45 -0
  36. data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
  37. data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
  38. data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
  39. data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
  40. data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
  41. data/spec/bitcoin/fixtures/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +34 -0
  42. data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
  43. data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  44. data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
  45. data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
  46. data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
  47. data/spec/bitcoin/fixtures/coinbase.json +24 -0
  48. data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  49. data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
  50. data/spec/bitcoin/fixtures/filteredblock-0.bin +0 -0
  51. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  52. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
  53. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  54. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
  55. data/spec/bitcoin/fixtures/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +259 -0
  56. data/spec/bitcoin/fixtures/rawblock-0.bin +0 -0
  57. data/spec/bitcoin/fixtures/rawblock-0.json +39 -0
  58. data/spec/bitcoin/fixtures/rawblock-1.bin +0 -0
  59. data/spec/bitcoin/fixtures/rawblock-1.json +39 -0
  60. data/spec/bitcoin/fixtures/rawblock-131025.bin +0 -0
  61. data/spec/bitcoin/fixtures/rawblock-131025.json +5063 -0
  62. data/spec/bitcoin/fixtures/rawblock-170.bin +0 -0
  63. data/spec/bitcoin/fixtures/rawblock-170.json +68 -0
  64. data/spec/bitcoin/fixtures/rawblock-9.bin +0 -0
  65. data/spec/bitcoin/fixtures/rawblock-9.json +39 -0
  66. data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
  67. data/spec/bitcoin/fixtures/rawblock-testnet-1151351.bin +0 -0
  68. data/spec/bitcoin/fixtures/rawblock-testnet-26478.bin +0 -0
  69. data/spec/bitcoin/fixtures/rawblock-testnet-26478.json +64 -0
  70. data/spec/bitcoin/fixtures/rawblock-testnet-265322.bin +0 -0
  71. data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
  72. data/spec/bitcoin/fixtures/rawtx-01.bin +0 -0
  73. data/spec/bitcoin/fixtures/rawtx-01.json +27 -0
  74. data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
  75. data/spec/bitcoin/fixtures/rawtx-02.bin +0 -0
  76. data/spec/bitcoin/fixtures/rawtx-02.json +27 -0
  77. data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
  78. data/spec/bitcoin/fixtures/rawtx-03.bin +0 -0
  79. data/spec/bitcoin/fixtures/rawtx-03.json +48 -0
  80. data/spec/bitcoin/fixtures/rawtx-04.json +27 -0
  81. data/spec/bitcoin/fixtures/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
  82. data/spec/bitcoin/fixtures/rawtx-05.json +23 -0
  83. data/spec/bitcoin/fixtures/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
  84. data/spec/bitcoin/fixtures/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
  85. data/spec/bitcoin/fixtures/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +27 -0
  86. data/spec/bitcoin/fixtures/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +23 -0
  87. data/spec/bitcoin/fixtures/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
  88. data/spec/bitcoin/fixtures/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
  89. data/spec/bitcoin/fixtures/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +37 -0
  90. data/spec/bitcoin/fixtures/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +24 -0
  91. data/spec/bitcoin/fixtures/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +23 -0
  92. data/spec/bitcoin/fixtures/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
  93. data/spec/bitcoin/fixtures/rawtx-p2wpkh.bin +0 -0
  94. data/spec/bitcoin/fixtures/rawtx-p2wpkh.json +67 -0
  95. data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  96. data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  97. data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  98. data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  99. data/spec/bitcoin/fixtures/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +27 -0
  100. data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  101. data/spec/bitcoin/fixtures/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
  102. data/spec/bitcoin/fixtures/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +41 -0
  103. data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  104. data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
  105. data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
  106. data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
  107. data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
  108. data/spec/bitcoin/fixtures/script_tests.json +1947 -0
  109. data/spec/bitcoin/fixtures/sighash.json +1004 -0
  110. data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
  111. data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
  112. data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
  113. data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
  114. data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
  115. data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
  116. data/spec/bitcoin/fixtures/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +64 -0
  117. data/spec/bitcoin/fixtures/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +64 -0
  118. data/spec/bitcoin/fixtures/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +139 -0
  119. data/spec/bitcoin/fixtures/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +64 -0
  120. data/spec/bitcoin/fixtures/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +64 -0
  121. data/spec/bitcoin/fixtures/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +28 -0
  122. data/spec/bitcoin/fixtures/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +23 -0
  123. data/spec/bitcoin/fixtures/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +64 -0
  124. data/spec/bitcoin/fixtures/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +64 -0
  125. data/spec/bitcoin/fixtures/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +64 -0
  126. data/spec/bitcoin/fixtures/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +34 -0
  127. data/spec/bitcoin/fixtures/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +64 -0
  128. data/spec/bitcoin/fixtures/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +64 -0
  129. data/spec/bitcoin/fixtures/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +28 -0
  130. data/spec/bitcoin/fixtures/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +30 -0
  131. data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
  132. data/spec/bitcoin/fixtures/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +23 -0
  133. data/spec/bitcoin/fixtures/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +64 -0
  134. data/spec/bitcoin/fixtures/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +32 -0
  135. data/spec/bitcoin/fixtures/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +64 -0
  136. data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
  137. data/spec/bitcoin/fixtures/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +38 -0
  138. data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
  139. data/spec/bitcoin/fixtures/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +23 -0
  140. data/spec/bitcoin/fixtures/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +30 -0
  141. data/spec/bitcoin/fixtures/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +64 -0
  142. data/spec/bitcoin/fixtures/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +23 -0
  143. data/spec/bitcoin/fixtures/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +27 -0
  144. data/spec/bitcoin/fixtures/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +28 -0
  145. data/spec/bitcoin/fixtures/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +64 -0
  146. data/spec/bitcoin/fixtures/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +40 -0
  147. data/spec/bitcoin/fixtures/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +64 -0
  148. data/spec/bitcoin/fixtures/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +64 -0
  149. data/spec/bitcoin/fixtures/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +64 -0
  150. data/spec/bitcoin/fixtures/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +64 -0
  151. data/spec/bitcoin/fixtures/tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json +23 -0
  152. data/spec/bitcoin/fixtures/tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json +30 -0
  153. data/spec/bitcoin/fixtures/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +23 -0
  154. data/spec/bitcoin/fixtures/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +23 -0
  155. data/spec/bitcoin/fixtures/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +27 -0
  156. data/spec/bitcoin/fixtures/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +64 -0
  157. data/spec/bitcoin/fixtures/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +27 -0
  158. data/spec/bitcoin/fixtures/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +28 -0
  159. data/spec/bitcoin/fixtures/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +36 -0
  160. data/spec/bitcoin/fixtures/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +23 -0
  161. data/spec/bitcoin/fixtures/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +28 -0
  162. data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
  163. data/spec/bitcoin/fixtures/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +406 -0
  164. data/spec/bitcoin/fixtures/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +35 -0
  165. data/spec/bitcoin/fixtures/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +64 -0
  166. data/spec/bitcoin/fixtures/txdp-1.txt +32 -0
  167. data/spec/bitcoin/fixtures/txdp-2-signed.txt +19 -0
  168. data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +14 -0
  169. data/spec/bitcoin/fixtures/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +1 -0
  170. data/spec/bitcoin/helpers/fake_blockchain.rb +183 -0
  171. data/spec/bitcoin/key_spec.rb +326 -0
  172. data/spec/bitcoin/network_spec.rb +50 -0
  173. data/spec/bitcoin/performance/storage_spec.rb +41 -0
  174. data/spec/bitcoin/protocol/addr_spec.rb +82 -0
  175. data/spec/bitcoin/protocol/alert_spec.rb +22 -0
  176. data/spec/bitcoin/protocol/aux_pow_spec.rb +45 -0
  177. data/spec/bitcoin/protocol/bip143_spec.rb +116 -0
  178. data/spec/bitcoin/protocol/block_spec.rb +208 -0
  179. data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
  180. data/spec/bitcoin/protocol/inv_spec.rb +134 -0
  181. data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
  182. data/spec/bitcoin/protocol/parser_spec.rb +50 -0
  183. data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +38 -0
  184. data/spec/bitcoin/protocol/ping_spec.rb +51 -0
  185. data/spec/bitcoin/protocol/reject.rb +17 -0
  186. data/spec/bitcoin/protocol/tx_spec.rb +894 -0
  187. data/spec/bitcoin/protocol/txin_spec.rb +45 -0
  188. data/spec/bitcoin/protocol/txout_spec.rb +27 -0
  189. data/spec/bitcoin/protocol/version_spec.rb +110 -0
  190. data/spec/bitcoin/script/opcodes_spec.rb +773 -0
  191. data/spec/bitcoin/script/script_spec.rb +971 -0
  192. data/spec/bitcoin/secp256k1_spec.rb +78 -0
  193. data/spec/bitcoin/spec_helper.rb +108 -0
  194. data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
  195. metadata +237 -0
@@ -0,0 +1,32 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (getblocks)' do
6
+
7
+ class Getblocks_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :version, :locator, :stop_hash
9
+ def on_getblocks(version, locator, stop_hash)
10
+ @version, @locator, @stop_hash = version, locator, stop_hash
11
+ end
12
+ end
13
+
14
+ before do
15
+ @parser = Bitcoin::Protocol::Parser.new( @handler = Getblocks_Handler.new )
16
+ @pkt = "f9beb4d9676574626c6f636b7300000065000000b3b7ad6e71110100026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000000000000000000000000000000000000000000000000000000000".htb
17
+ @parser.parse(@pkt + "AAAA").should == "AAAA"
18
+ end
19
+
20
+ it 'parses getblocks' do
21
+ @handler.version.should == 70001
22
+ @handler.locator.should == [
23
+ "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
24
+ "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" ]
25
+ @handler.stop_hash.should == "00"*32
26
+ end
27
+
28
+ it 'builds getblocks' do
29
+ Bitcoin::Protocol.getblocks_pkt(70001, @handler.locator).hth.should == @pkt.hth
30
+ end
31
+
32
+ end
@@ -0,0 +1,134 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser - Inventory Vectors' do
6
+
7
+ class Test_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :tx_inv, :block_inv, :err
9
+ def on_inv_transaction(hash); (@tx_inv ||= []) << hash.hth; end
10
+ def on_get_transaction(hash); (@tx_inv ||= []) << hash.hth; end
11
+ def on_inv_block(hash); (@block_inv ||= []) << hash.hth; end
12
+ def on_get_block(hash); (@block_inv ||= []) << hash.hth; end
13
+ def on_error(*err); (@err ||= []) << err; end
14
+ end
15
+
16
+
17
+ it 'parses inv (transaction)' do
18
+ pkt = [
19
+ "f9 be b4 d9 69 6e 76 00 00 00 00 00 00 00 00 00 49 00 00 00 11 ea 1c 91 02 01 00 00 00 e0 41 c2 38 f7 32 1a 68 0a 34 06 bf fd 72 12 e3 d1 2c b5 12 2a 8c 0b 52 76 de 82 30 b1 00 7a 42 01 00 00 00 33 00 09 71 a9 70 7b 6c 6d 6e 77 aa 2e ac 43 f3 e5 67 84 cb 61 b2 35 fb 8d fe e0 86 8b 40 7c f3"
20
+ .split(" ").join].pack("H*")
21
+
22
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
23
+ parser.parse(pkt + "AAAA").should == "AAAA"
24
+
25
+ handler.tx_inv.should == [
26
+ "427a00b13082de76520b8c2a12b52cd1e31272fdbf06340a681a32f738c241e0",
27
+ "f37c408b86e0fe8dfb35b261cb8467e5f343ac2eaa776e6d6c7b70a971090033"
28
+ ]
29
+ end
30
+
31
+
32
+ it 'parses getdata (transaction)' do
33
+ # 000013C4 f9 be b4 d9 67 65 74 64 61 74 61 00 00 00 00 00 ....getd ata.....
34
+ # 000013D4 25 00 00 00 c5 38 cd bb 01 01 00 00 00 b4 02 2d %....8.. .......-
35
+ # 000013E4 9f e5 28 fb 90 70 50 01 16 4b 0c c3 a8 f5 a1 9c ..(..pP. .K......
36
+ # 000013F4 b8 ed 02 bf d4 fc 2c b6 25 66 d1 9d 6e ......,. %f..n
37
+
38
+ pkt = [
39
+ "f9 be b4 d9 67 65 74 64 61 74 61 00 00 00 00 00 25 00 00 00 c5 38 cd bb 01 01 00 00 00 b4 02 2d 9f e5 28 fb 90 70 50 01 16 4b 0c c3 a8 f5 a1 9c b8 ed 02 bf d4 fc 2c b6 25 66 d1 9d 6e"
40
+ .split(" ").join].pack("H*")
41
+
42
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
43
+ parser.parse(pkt + "AAAA").should == "AAAA"
44
+
45
+ handler.tx_inv.should == [
46
+ "6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4"
47
+ ]
48
+ end
49
+
50
+
51
+ it 'parses inv (block)' do
52
+ # 00003C27 f9 be b4 d9 69 6e 76 00 00 00 00 00 00 00 00 00 ....inv. ........
53
+ # 00003C37 25 00 00 00 ae 13 a1 04 01 02 00 00 00 9d b9 c4 %....... ........
54
+ # 00003C47 e2 7c 5b cd 3f 62 e1 af 18 fd 9d 81 6d 6c 6b c7 .|[.?b.. ....mlk.
55
+ # 00003C57 b2 26 0a 39 c5 49 39 00 00 00 00 00 00 .&.9.I9. .....
56
+ pkt = [
57
+ "f9 be b4 d9 69 6e 76 00 00 00 00 00 00 00 00 00 25 00 00 00 ae 13 a1 04 01 02 00 00 00 9d b9 c4 e2 7c 5b cd 3f 62 e1 af 18 fd 9d 81 6d 6c 6b c7 b2 26 0a 39 c5 49 39 00 00 00 00 00 00"
58
+ .split(" ").join].pack("H*")
59
+
60
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
61
+ parser.parse(pkt + "AAAA").should == "AAAA"
62
+ handler.block_inv.should == [
63
+ "0000000000003949c5390a26b2c76b6c6d819dfd18afe1623fcd5b7ce2c4b99d"
64
+ ]
65
+ end
66
+
67
+
68
+ it 'parses getdata (block)' do
69
+ # 000039E3 f9 be b4 d9 67 65 74 64 61 74 61 00 00 00 00 00 ....getd ata.....
70
+ # 000039F3 25 00 00 00 ae 13 a1 04 01 02 00 00 00 9d b9 c4 %....... ........
71
+ # 00003A03 e2 7c 5b cd 3f 62 e1 af 18 fd 9d 81 6d 6c 6b c7 .|[.?b.. ....mlk.
72
+ # 00003A13 b2 26 0a 39 c5 49 39 00 00 00 00 00 00 .&.9.I9. .....
73
+ pkt = [
74
+ "f9 be b4 d9 67 65 74 64 61 74 61 00 00 00 00 00 25 00 00 00 ae 13 a1 04 01 02 00 00 00 9d b9 c4 e2 7c 5b cd 3f 62 e1 af 18 fd 9d 81 6d 6c 6b c7 b2 26 0a 39 c5 49 39 00 00 00 00 00 00"
75
+ .split(" ").join].pack("H*")
76
+
77
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
78
+ parser.parse(pkt + "AAAA").should == "AAAA"
79
+
80
+ handler.block_inv.should == [
81
+ "0000000000003949c5390a26b2c76b6c6d819dfd18afe1623fcd5b7ce2c4b99d"
82
+ ]
83
+ end
84
+
85
+
86
+ it 'parses getblocks' do
87
+ class Test_Handler < Bitcoin::Protocol::Handler
88
+ attr_reader :pkt
89
+ def on_getblocks(version, hashes, stop_hash); @pkt = { :version => version, :locator_hashes => hashes, :stop_hash => stop_hash }; end
90
+ end
91
+
92
+ locator_hashes = ["00000000068866924696f410b778911316f92035e9b69b62afa03573974fd750", "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"]
93
+ stop_hash = "0000000000000000000000000000000000000000000000000000000000000000"
94
+ pkt = Bitcoin::Protocol.getblocks_pkt( Bitcoin.network[:protocol_version], locator_hashes )
95
+
96
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
97
+ parser.parse(pkt + "AAAA").should == "AAAA"
98
+
99
+ handler.pkt.should == {
100
+ :version => Bitcoin.network[:protocol_version],
101
+ :locator_hashes => locator_hashes,
102
+ :stop_hash => "0000000000000000000000000000000000000000000000000000000000000000"
103
+ }
104
+ end
105
+
106
+ it 'parses getheaders' do
107
+ class Test_Handler < Bitcoin::Protocol::Handler
108
+ attr_reader :pkt
109
+ def on_getheaders(version, hashes, stop_hash); @pkt = { :version => version, :locator_hashes => hashes, :stop_hash => stop_hash }; end
110
+ end
111
+
112
+ locator_hashes = ["00000000068866924696f410b778911316f92035e9b69b62afa03573974fd750", "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"]
113
+ stop_hash = "0000000000000000000000000000000000000000000000000000000000007e57"
114
+ pkt = Bitcoin::Protocol.getblocks_pkt( Bitcoin.network[:protocol_version], locator_hashes, stop_hash )
115
+
116
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
117
+ parser.parse(pkt + "AAAA").should == "AAAA"
118
+
119
+ handler.pkt.should == {
120
+ :version => Bitcoin.network[:protocol_version],
121
+ :locator_hashes => locator_hashes,
122
+ :stop_hash => "0000000000000000000000000000000000000000000000000000000000007e57"
123
+ }
124
+ end
125
+
126
+ it 'parses broken inv packet' do
127
+ pkt = [("01 00 00 00 00" + " 00"*32).split(" ").join].pack("H*")
128
+ parser = Bitcoin::Protocol::Parser.new( handler = Test_Handler.new )
129
+ parser.parse_inv(pkt).should == nil
130
+ handler.tx_inv.should == nil
131
+ handler.err.should == [[:parse_inv, pkt[1..-1]]]
132
+ end
133
+
134
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (notfound)' do
6
+
7
+ class Notfound_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :notfound
9
+ def on_notfound(type, hash); (@notfound ||= []) << [type, hash.hth]; end
10
+ end
11
+
12
+ before do
13
+ @parser = Bitcoin::Protocol::Parser.new( @handler = Notfound_Handler.new )
14
+ end
15
+
16
+ it 'parses notfound block message' do
17
+ payload = "\x01\x01\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
18
+ @parser.parse(Bitcoin::Protocol.pkt("notfound", payload) + "AAAA").should == "AAAA"
19
+ @handler.notfound.should == [
20
+ [:tx, "2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a"]
21
+ ]
22
+ end
23
+
24
+ it 'parses notfound tx message' do
25
+ payload = "\x01\x02\x00\x00\x00:\xE2\x93bDJ\x01\xA9|\xDA>0\x8F\a\xA3L\n\xEF\x0E\xD2\xF2\xC6\xCE\xCA(\xD19}\x80*h+"
26
+ @parser.parse(Bitcoin::Protocol.pkt("notfound", payload) + "AAAA").should == "AAAA"
27
+ @handler.notfound.should == [
28
+ [:block, "2b682a807d39d128cacec6f2d20eef0a4ca3078f303eda7ca9014a446293e23a"]
29
+ ]
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+ require 'minitest/mock'
5
+
6
+ include Bitcoin::Protocol
7
+
8
+ describe 'Bitcoin::Protocol::Parser' do
9
+
10
+
11
+ before {
12
+ @pkt= [
13
+ "f9 be b4 d9", # magic head
14
+ "69 6e 76 00 00 00 00 00 00 00 00 00", # command ("inv")
15
+ "49 00 00 00", # message length
16
+ "11 ea 1c 91", # checksum
17
+
18
+ "02", # n hashes
19
+ "01 00 00 00", # type (1=tx)
20
+ "e0 41 c2 38 f7 32 1a 68 0a 34 06 bf fd 72 12 e3 d1 2c b5 12 2a 8c 0b 52 76 de 82 30 b1 00 7a 42",
21
+ "01 00 00 00", # type (1=tx)
22
+ "33 00 09 71 a9 70 7b 6c 6d 6e 77 aa 2e ac 43 f3 e5 67 84 cb 61 b2 35 fb 8d fe e0 86 8b 40 7c f3"
23
+ ].map{|s| s.split(" ")}.flatten.join.htb
24
+ @handler = MiniTest::Mock.new }
25
+ after { @handler.verify }
26
+
27
+ it 'should call appropriate handler' do
28
+ @handler.expect(:on_inv_transaction, nil, [@pkt[29..60].reverse])
29
+ @handler.expect(:on_inv_transaction, nil, [@pkt[-32..-1].reverse])
30
+ Parser.new( @handler ).parse( @pkt ).should == ""
31
+ end
32
+
33
+ it 'should count total packets and bytes' do
34
+ parser = Parser.new
35
+ parser.parse @pkt
36
+ parser.stats.should == {"total_packets"=>1, "total_bytes"=>73, "total_errors" => 0, "inv"=>1}
37
+ end
38
+
39
+ it 'should call error handler for unknown command' do
40
+ @handler.expect(:on_error, nil, [:unknown_packet, ["foo", "626172"]])
41
+ Parser.new( @handler ).process_pkt('foo', "bar").should == nil
42
+ end
43
+
44
+ it 'should count total errors' do
45
+ parser = Parser.new
46
+ parser.process_pkt('foo', 'bar')
47
+ parser.stats['total_errors'].should == 1
48
+ end
49
+
50
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../spec_helper.rb'
2
+ require 'set'
3
+
4
+
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
+ #
9
+ describe 'Bitcoin::Protocol::PartialMerkleTree' do
10
+ it "initialize" do
11
+ hashes = [
12
+ '4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb',
13
+ 'ca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb',
14
+ 'bb15ac1d57d0182aaee61c74743a9c4f785895e563909bafec45c9a2b0ff3181',
15
+ 'd77706be8b1dcc91112eada86d424e2d0a8907c3488b6e44fda5a74a25cbc7d6',
16
+ 'bb4fa04245f4ac8a1a571d5537eac24adca1454d65eda446055479af6c6d4dd3',
17
+ 'c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db6615c6abc5',
18
+ 'ca042127bfaf9f44ebce29cb29c6df9d05b47f35b2edff4f0064b578ab741fa7',
19
+ '8276222651209fe1a2c4c0fa1c58510aec8b090dd1eb1f82f9d261b8273b525b',
20
+ ].map(&:htb)
21
+ tree = Bitcoin::P::PartialMerkleTree.new(12, hashes, 'ff1a'.htb)
22
+ tree.set_value
23
+
24
+ tx_hashes = Set.new(tree.tx_hashes)
25
+ # following 6 are leaves (tx_hash) of merkle tree
26
+ tx_hashes.include?('bb28a1a5b3a02e7657a81c38355d56c6f05e80b9219432e3352ddcfc3cb6304c').should == true
27
+ tx_hashes.include?('fbde5d03b027d2b9ba4cf5d4fecab9a99864df2637b25ea4cbcb1796ff6550ca').should == true
28
+ tx_hashes.include?('8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb').should == true
29
+ tx_hashes.include?('c5abc61566dbb1c4bce5e1fda7b66bed22eb2130cea4b721690bc1488465abc9').should == true
30
+ tx_hashes.include?('d6c7cb254aa7a5fd446e8b48c307890a2d4e426da8ad2e1191cc1d8bbe0677d7').should == true
31
+ tx_hashes.include?('a71f74ab78b564004fffedb2357fb4059ddfc629cb29ceeb449fafbf272104ca').should == true
32
+ # following 2 are edge node of merkle tree
33
+ tx_hashes.include?('d34d6d6caf79540546a4ed654d45a1dc4ac2ea37551d571a8aacf44542a04fbb').should == false
34
+ tx_hashes.include?('5b523b27b861d2f9821febd10d098bec0a51581cfac0c4a2e19f205126227682').should == false
35
+
36
+ tree.root.value.should == '7fe79307aeb300d910d9c4bec5bacb4c7e114c7dfd6789e19f3a733debb3bb6a'
37
+ end
38
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (ping/pong)' do
6
+
7
+ class Ping_Handler < Bitcoin::Protocol::Handler
8
+ attr_reader :nonce
9
+ def on_ping(nonce)
10
+ @nonce = nonce
11
+ end
12
+ def on_pong(nonce)
13
+ @nonce = nonce
14
+ end
15
+ end
16
+
17
+ before do
18
+ @parser = Bitcoin::Protocol::Parser.new( @handler = Ping_Handler.new )
19
+ end
20
+
21
+ it 'parses ping without nonce' do
22
+ @parser.parse(Bitcoin::Protocol.pkt("ping", "") + "AAAA").should == "AAAA"
23
+ @handler.nonce.should == nil
24
+ end
25
+
26
+ it 'parses ping with nonce' do
27
+ @parser.parse(Bitcoin::Protocol.pkt("ping", [12345].pack("Q")) + "AAAA").should == "AAAA"
28
+ @handler.nonce.should == 12345
29
+ end
30
+
31
+ it 'builds ping without nonce' do
32
+ @parser.parse(Bitcoin::Protocol::ping_pkt)
33
+ @handler.nonce.should != nil
34
+ end
35
+
36
+ it 'builds ping with nonce' do
37
+ @parser.parse(Bitcoin::Protocol::ping_pkt(12345))
38
+ @handler.nonce.should == 12345
39
+ end
40
+
41
+ it 'parses pong' do
42
+ @parser.parse(Bitcoin::Protocol.pkt("pong", [12345].pack("Q")) + "AAAA").should == "AAAA"
43
+ @handler.nonce.should == 12345
44
+ end
45
+
46
+ it 'builds pong' do
47
+ @parser.parse(Bitcoin::Protocol::pong_pkt(12345))
48
+ @handler.nonce.should == 12345
49
+ end
50
+
51
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ describe 'Bitcoin::Protocol::Parser (reject)' do
6
+
7
+ it 'parses alert' do
8
+ payload = "\x02tx\x10\bcoinbase\xB5\x93\x84\x8D\x99\xF4\x1AE\xE9\xD2\x90T\x9919\xF0X %\xBBE\x19\x19\x86\xBC\r\x812\x7F\xC4\xEDN"
9
+
10
+ alert = Bitcoin::Protocol::Reject.parse(payload)
11
+ alert.message.should == "tx"
12
+ alert.ccode.should == :invalid
13
+ alert.reason.should == "coinbase"
14
+ alert.tx_hash.should == "4eedc47f32810dbc86191945bb252058f03931995490d2e9451af4998d8493b5"
15
+ end
16
+
17
+ end
@@ -0,0 +1,894 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper.rb'
4
+
5
+ include Bitcoin::Protocol
6
+
7
+ describe 'Tx' do
8
+
9
+ @payload = [
10
+ fixtures_file('rawtx-01.bin'),
11
+ fixtures_file('rawtx-02.bin'),
12
+ fixtures_file('rawtx-03.bin'),
13
+ fixtures_file('rawtx-p2wpkh.bin'),
14
+ ]
15
+
16
+ @json = [
17
+ fixtures_file('rawtx-01.json'),
18
+ fixtures_file('rawtx-02.json'),
19
+ fixtures_file('rawtx-03.json'),
20
+ fixtures_file('rawtx-p2wpkh.json')
21
+ ]
22
+
23
+
24
+ it '#new' do
25
+ proc{
26
+ Tx.new( nil )
27
+ @payload.each{|payload| Tx.new( payload ) }
28
+ }.should.not.raise Exception
29
+
30
+ proc{
31
+ Tx.new( @payload[0][0..20] )
32
+ }.should.raise Exception
33
+
34
+ # Deserializing a new, empty transaction works
35
+ Tx.new(Tx.new.to_payload)
36
+ end
37
+
38
+ it '#parse_data' do
39
+ tx = Tx.new( nil )
40
+
41
+ tx.hash.should == nil
42
+ tx.parse_data( @payload[0] ).should == true
43
+ tx.hash.size.should == 64
44
+ tx.payload.should == @payload[0]
45
+
46
+ tx = Tx.new( nil )
47
+ tx.parse_data( @payload[0] + "AAAA" ).should == "AAAA"
48
+ tx.hash.size.should == 64
49
+ tx.payload.should == @payload[0]
50
+ end
51
+
52
+ it '#parse_witness_data' do
53
+ tx = Tx.new( @payload[3] )
54
+ tx.hash.size.should == 64
55
+ tx.payload.should == @payload[3]
56
+
57
+ tx = Tx.new( @payload[3] + "AAAA" )
58
+ tx.hash.size.should == 64
59
+ tx.payload.should == @payload[3]
60
+ end
61
+
62
+ it '#hash' do
63
+ tx = Tx.new( @payload[0] )
64
+ tx.hash.size.should == 64
65
+ tx.hash.should == "6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4"
66
+ tx.binary_hash.should == "\xB4\x02-\x9F\xE5(\xFB\x90pP\x01\x16K\f\xC3\xA8\xF5\xA1\x9C\xB8\xED\x02\xBF\xD4\xFC,\xB6%f\xD1\x9Dn"
67
+
68
+ tx = Tx.new(@payload[3])
69
+ tx.hash.size.should == 64
70
+ tx.hash.should == "f22f5168cf0bc55a31003b0fc532152da551e1ec4289c4fd92e7ec512c6e87a0"
71
+ end
72
+
73
+ it '#witness_hash' do
74
+ tx = Tx.new(@payload[3])
75
+ tx.witness_hash.size.should == 64
76
+ tx.witness_hash.should == "c9609ed4d7e60ebcf4cce2854568b54a855a12b5bda15433ca96e72cd445a5cf"
77
+ end
78
+
79
+ it '#normalized_hash' do
80
+ tx = Tx.new( @payload[0] )
81
+ tx.normalized_hash.size.should == 64
82
+ tx.normalized_hash.should == "393a12b91d5b5e2449f2d27a22ffc0af937c3796a08c8213cc37690b10302e40"
83
+
84
+ new_tx = JSON.parse(tx.to_json)
85
+ script = Bitcoin::Script.from_string(new_tx['in'][0]['scriptSig'])
86
+ script.chunks[0].bitcoin_pushdata = Bitcoin::Script::OP_PUSHDATA2
87
+ script.chunks[0].bitcoin_pushdata_length = script.chunks[0].bytesize
88
+ new_tx['in'][0]['scriptSig'] = script.to_string
89
+ new_tx = Bitcoin::P::Tx.from_hash(new_tx, false)
90
+
91
+ new_tx.hash.should != tx.hash
92
+ new_tx.normalized_hash.size.should == 64
93
+ new_tx.normalized_hash.should == "393a12b91d5b5e2449f2d27a22ffc0af937c3796a08c8213cc37690b10302e40"
94
+ end
95
+
96
+ it '#to_payload' do
97
+ tx = Tx.new( @payload[0] )
98
+ tx.to_payload.size.should == @payload[0].size
99
+ tx.to_payload.should == @payload[0]
100
+ end
101
+
102
+ it '#to_witness_payload' do
103
+ tx = Tx.new( @payload[3] )
104
+ tx.to_witness_payload.size.should == @payload[3].size
105
+ tx.to_witness_payload.should == @payload[3]
106
+ end
107
+
108
+ it '#to_hash' do
109
+ tx = Tx.new( @payload[0] )
110
+ tx.to_hash.keys.should == ["hash", "ver", "vin_sz", "vout_sz", "lock_time", "size", "in", "out"]
111
+
112
+ # witness tx
113
+ tx = Tx.new( @payload[3] )
114
+ tx.to_hash.keys.should == ["hash", "ver", "vin_sz", "vout_sz", "lock_time", "size", "in", "out"]
115
+ end
116
+
117
+ it 'Tx.from_hash' do
118
+ orig_tx = Tx.new( @payload[0] )
119
+ tx = Tx.from_hash( orig_tx.to_hash )
120
+ tx.payload.should == @payload[0]
121
+ tx.to_payload.size.should == @payload[0].size
122
+ tx.to_payload.should == @payload[0]
123
+ tx.to_hash.should == orig_tx.to_hash
124
+ Tx.binary_from_hash( orig_tx.to_hash ).should == @payload[0]
125
+
126
+ h = orig_tx.to_hash.merge("ver" => 123)
127
+ -> { tx = Tx.from_hash(h) }.should.raise(Exception)
128
+ .message.should == "Tx hash mismatch! Claimed: 6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4, Actual: 395cd28c334ac84ed125ec5ccd5bc29eadcc96b79c337d0a87a19df64ea3b548"
129
+
130
+ # witness tx(P2WPKH)
131
+ orig_tx = Tx.new( @payload[3] )
132
+ tx = Tx.from_hash( orig_tx.to_hash )
133
+ tx.payload.should == @payload[3]
134
+ tx.to_witness_payload.size.should == @payload[3].size
135
+ tx.to_witness_payload.should == @payload[3]
136
+ tx.to_hash == orig_tx.to_hash
137
+ end
138
+
139
+ it 'Tx.binary_from_hash' do
140
+ orig_tx = Tx.new( @payload[0] )
141
+ Tx.binary_from_hash( orig_tx.to_hash ).size.should == @payload[0].size
142
+ Tx.binary_from_hash( orig_tx.to_hash ).should == @payload[0]
143
+
144
+ orig_tx = Tx.new( @payload[3] )
145
+ Tx.binary_from_hash( orig_tx.to_hash ).size.should == @payload[3].size
146
+ Tx.binary_from_hash( orig_tx.to_hash ).should == @payload[3]
147
+ end
148
+
149
+ it '#to_json' do
150
+ tx = Tx.new( @payload[0] )
151
+ tx.to_json.should == @json[0]
152
+
153
+ tx = Tx.new( @payload[1] )
154
+ tx.to_json.should == @json[1]
155
+
156
+ tx = Tx.new( @payload[2] )
157
+ tx.to_json.should == @json[2]
158
+
159
+ tx = Tx.new( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin') )
160
+ tx.to_json.should == fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json')
161
+
162
+ tx = Tx.new(@payload[3])
163
+ tx.to_json.should == @json[3]
164
+ end
165
+
166
+ it 'Tx.from_json' do
167
+ tx = Tx.from_json( json_string = fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json') )
168
+ tx.to_json.should == json_string
169
+
170
+ tx = Tx.from_json( json_string = fixtures_file('rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json') )
171
+ tx.to_json.should == json_string
172
+
173
+ tx = Tx.from_json( json_string = fixtures_file('rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json') )
174
+ tx.to_payload.should == fixtures_file('rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin')
175
+ tx.to_json.should == json_string
176
+
177
+ tx = Tx.from_json( fixtures_file('rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json') )
178
+ Tx.new( tx.to_payload ).to_json.should == tx.to_json
179
+ tx.hash.should == 'ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5'
180
+
181
+ # coinbase tx with non-default sequence
182
+ tx = Tx.from_json( json=fixtures_file('0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json'))
183
+ Tx.new( tx.to_payload ).to_json.should == json
184
+
185
+ # toshi format
186
+ Tx.from_json(fixtures_file('rawtx-02-toshi.json')).to_payload.should == Tx.from_json(fixtures_file('rawtx-02.json')).to_payload
187
+ Tx.from_json(fixtures_file('rawtx-03-toshi.json')).to_payload.should == Tx.from_json(fixtures_file('rawtx-03.json')).to_payload
188
+ Tx.from_json(fixtures_file('coinbase-toshi.json')).to_payload.should == Tx.from_json(fixtures_file('coinbase.json')).to_payload
189
+
190
+ # witness tx
191
+ tx = Tx.from_json(json_string = fixtures_file('rawtx-p2wpkh.json'))
192
+ tx.to_witness_payload.should == @payload[3]
193
+ tx.to_json == json_string
194
+ end
195
+
196
+ it 'Tx.binary_from_json' do
197
+ Tx.binary_from_json( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json') ).should ==
198
+ fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin')
199
+ end
200
+
201
+ it 'compares arrays of bytes' do
202
+ # This function is used in validating an ECDSA signature's S value
203
+ c1 = []
204
+ c2 = []
205
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 0
206
+
207
+ c1 = [0]
208
+ c2 = []
209
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 0
210
+
211
+ c1 = []
212
+ c2 = [0]
213
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 0
214
+
215
+ c1 = [5]
216
+ c2 = [5]
217
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 0
218
+
219
+ c1 = [04]
220
+ c2 = [5]
221
+ Bitcoin::Script::compare_big_endian(c1, c2).should == -1
222
+
223
+ c1 = [4]
224
+ c2 = [05]
225
+ Bitcoin::Script::compare_big_endian(c1, c2).should == -1
226
+
227
+ c1 = [5]
228
+ c2 = [4]
229
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 1
230
+
231
+ c1 = [05]
232
+ c2 = [004]
233
+ Bitcoin::Script::compare_big_endian(c1, c2).should == 1
234
+
235
+ end
236
+
237
+ it 'validates ECDSA signature format' do
238
+ # TX 3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae
239
+ sig_orig = ["304502210088984573e3e4f33db7df6aea313f1ce67a3ef3532ea89991494c7f018258371802206ceefc9291450dbd40d834f249658e0f64662d52a41cf14e20c9781144f2fe0701"].pack("H*")
240
+ Bitcoin::Script::is_der_signature?(sig_orig).should == true
241
+ Bitcoin::Script::is_defined_hashtype_signature?(sig_orig).should == true
242
+
243
+ # Trimmed to be too short
244
+ sig = sig_orig.slice(0, 8)
245
+ Bitcoin::Script::is_der_signature?(sig).should == false
246
+
247
+ # Zero-padded to be too long
248
+ sig = String.new(sig_orig)
249
+ sig << 0x00
250
+ sig << 0x00
251
+ Bitcoin::Script::is_der_signature?(sig).should == false
252
+
253
+ # Wrong first byte
254
+ sig_bytes = sig_orig.unpack("C*")
255
+ sig_bytes[0] = 0x20
256
+ sig = sig_bytes.pack("C*")
257
+ Bitcoin::Script::is_der_signature?(sig).should == false
258
+
259
+ # Length byte broken
260
+ sig_bytes = sig_orig.unpack("C*")
261
+ sig_bytes[1] = 0x20
262
+ sig = sig_bytes.pack("C*")
263
+ Bitcoin::Script::is_der_signature?(sig).should == false
264
+
265
+ # Incorrect R value type
266
+ sig_bytes = sig_orig.unpack("C*")
267
+ sig_bytes[2] = 0x03
268
+ sig = sig_bytes.pack("C*")
269
+ Bitcoin::Script::is_der_signature?(sig).should == false
270
+
271
+ # R value length infeasibly long
272
+ sig_bytes = sig_orig.unpack("C*")
273
+ sig_bytes[3] = sig_orig.size - 4
274
+ sig = sig_bytes.pack("C*")
275
+ Bitcoin::Script::is_der_signature?(sig).should == false
276
+
277
+ # Negative R value
278
+ sig_bytes = sig_orig.unpack("C*")
279
+ sig_bytes[4] = 0x80 | sig_bytes[4]
280
+ sig = sig_bytes.pack("C*")
281
+ Bitcoin::Script::is_der_signature?(sig).should == false
282
+
283
+ # R value excessively padded
284
+ sig_bytes = sig_orig.unpack("C*")
285
+ sig_bytes[5] = 0x00
286
+ sig = sig_bytes.pack("C*")
287
+ Bitcoin::Script::is_der_signature?(sig).should == false
288
+
289
+ # Incorrect S value type
290
+ sig_bytes = sig_orig.unpack("C*")
291
+ sig_bytes[37] = 0x03
292
+ sig = sig_bytes.pack("C*")
293
+ Bitcoin::Script::is_der_signature?(sig).should == false
294
+
295
+ # Zero S length
296
+ sig_bytes = sig_orig.unpack("C*")
297
+ sig_bytes[38] = 0x00
298
+ sig = sig_bytes.pack("C*")
299
+ Bitcoin::Script::is_der_signature?(sig).should == false
300
+
301
+ # Negative S value
302
+ sig_bytes = sig_orig.unpack("C*")
303
+ sig_bytes[39] = 0x80 | sig_bytes[39]
304
+ sig = sig_bytes.pack("C*")
305
+ Bitcoin::Script::is_der_signature?(sig).should == false
306
+ end
307
+
308
+ it '#verify_input_signature' do
309
+ # transaction-2 of block-170
310
+ tx = Tx.new( fixtures_file('rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin') )
311
+ tx.hash.should == "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
312
+
313
+ # transaction-1 (coinbase) of block-9
314
+ outpoint_tx = Tx.new( fixtures_file('rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin') )
315
+ outpoint_tx.hash.should == "0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9"
316
+
317
+ tx.verify_input_signature(0, outpoint_tx).should == true
318
+
319
+ # Only one test where we provide the TxOut is needed since when providing
320
+ # the full outpoint_tx the verification logic doesn't change.
321
+ tx.verify_input_signature(0, outpoint_tx.out[0]).should == true
322
+
323
+ tx = Tx.from_json( fixtures_file('rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json') )
324
+ tx.hash.should == 'c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73'
325
+
326
+ outpoint_tx = Tx.from_json( fixtures_file('rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json') )
327
+ outpoint_tx.hash.should == '406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602'
328
+
329
+ tx.verify_input_signature(0, outpoint_tx).should == true
330
+
331
+
332
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json'))
333
+ tx.hash.should == '0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae'
334
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json'))
335
+ outpoint_tx.hash.should == 'aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4'
336
+ tx.verify_input_signature(0, outpoint_tx).should == true
337
+
338
+ # SIGHASH_ANYONECANPAY transaction
339
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json'))
340
+ tx.hash.should == '51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e'
341
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json'))
342
+ outpoint_tx.hash.should == '761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6'
343
+ tx.verify_input_signature(0, outpoint_tx).should == true
344
+
345
+ # BIP12/OP_EVAL does't exist.
346
+ tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json'))
347
+ tx.hash.should == '03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99'
348
+ outpoint_tx = Bitcoin::Protocol::Tx.from_json(fixtures_file('f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json'))
349
+ outpoint_tx.hash.should == 'f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b'
350
+ tx.verify_input_signature(0, outpoint_tx).should == true
351
+
352
+ # (SIGHASH_ANYONECANPAY | SIGHASH_SINGLE) p2sh transaction
353
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json'))
354
+ tx.hash.should == "7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d"
355
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json'))
356
+ outpoint_tx.hash.should == "3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477"
357
+ tx.verify_input_signature(0, outpoint_tx).should == true
358
+
359
+ # SIGHHASH_SINGLE - https://bitcointalk.org/index.php?topic=260595.0
360
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json'))
361
+ tx.hash.should == "315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f"
362
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json'))
363
+ outpoint_tx.hash.should == "69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc"
364
+ tx.verify_input_signature(0, outpoint_tx).should == true
365
+ tx.verify_input_signature(1, outpoint_tx).should == true
366
+
367
+ # 0:1:01 <signature> 0:1:01 0:1:00 <pubkey> OP_SWAP OP_1ADD OP_CHECKMULTISIG
368
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json'))
369
+ tx.hash.should == "cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2"
370
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json'))
371
+ outpoint_tx.hash.should == "514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58"
372
+ tx.verify_input_signature(0, outpoint_tx).should == true
373
+
374
+ # OP_CHECKSIG with OP_0 from mainnet a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954 output 0
375
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json'))
376
+ tx.hash.should == "9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28"
377
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json'))
378
+ outpoint_tx.hash.should == "a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954"
379
+ tx.verify_input_signature(0, outpoint_tx).should == true
380
+
381
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
382
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json'))
383
+ tx.hash.should == "46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa"
384
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json'))
385
+ outpoint_tx.hash.should == "bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224"
386
+ tx.verify_input_signature(0, outpoint_tx).should == true
387
+
388
+ # drop OP_CODESEPARATOR in subscript for signature_hash_for_input
389
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json'))
390
+ tx.hash.should == "aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8"
391
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json'))
392
+ outpoint_tx.hash.should == "326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e"
393
+ tx.verify_input_signature(0, outpoint_tx).should == true
394
+
395
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input
396
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json'))
397
+ tx.hash.should == "6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190"
398
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json'))
399
+ outpoint_tx.hash.should == "a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944"
400
+ tx.verify_input_signature(0, outpoint_tx).should == true
401
+
402
+ # drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input when used in ScriptSig
403
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json'))
404
+ tx.hash.should == "eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb"
405
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json'))
406
+ outpoint_tx.hash.should == "b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d"
407
+ tx.verify_input_signature(1, outpoint_tx).should == true
408
+
409
+ # OP_DUP OP_HASH160
410
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json'))
411
+ tx.hash.should == "5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f"
412
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json'))
413
+ outpoint_tx.hash.should == "b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9"
414
+ tx.verify_input_signature(0, outpoint_tx).should == true
415
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json'))
416
+ outpoint_tx.hash.should == "ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742"
417
+ tx.verify_input_signature(1, outpoint_tx).should == true
418
+
419
+ # testnet3 e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009
420
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json'))
421
+ tx.hash.should == "e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009"
422
+ prev_txs = {}
423
+ tx.in.map{|i| i.previous_output }.uniq.each{|i| prev_txs[i] = Bitcoin::P::Tx.from_json(fixtures_file("tx-#{i}.json")) }
424
+ tx.in.each.with_index{|i,idx|
425
+ tx.verify_input_signature(idx, prev_txs[i.previous_output]).should == true
426
+ }
427
+
428
+ # BIP62 rule #2 - spend transaction has operations in its signature
429
+ tx = Tx.new( fixtures_file('rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin') )
430
+ tx.hash.should == "3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e"
431
+ outpoint_tx = Tx.new( fixtures_file('rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin') )
432
+ outpoint_tx.hash.should == "04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4"
433
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i).should == true
434
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i, verify_sigpushonly: true).should == false
435
+
436
+ # BIP62 rule #6 - spend transaction has an unused "0" on the signature stack
437
+ tx = Tx.new( fixtures_file('rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin') )
438
+ tx.hash.should == "0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f"
439
+ outpoint_tx = Tx.new( fixtures_file('rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin') )
440
+ outpoint_tx.hash.should == "f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5"
441
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i).should == true
442
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i, verify_cleanstack: true).should == false
443
+
444
+ # Ensure BIP62 is applied to P2SH scripts
445
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json'))
446
+ tx.hash.should == "7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d"
447
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json'))
448
+ outpoint_tx.hash.should == "3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477"
449
+ tx.verify_input_signature(0, outpoint_tx).should == true
450
+ tx.verify_input_signature(0, outpoint_tx, Time.now.to_i, verify_low_s: true).should == false
451
+
452
+ # testnet3 P2SH check
453
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json'))
454
+ tx.hash.should == "156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a"
455
+ outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json'))
456
+ outpoint_tx.hash.should == "8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c"
457
+ tx.verify_input_signature(0, outpoint_tx).should == true
458
+ end
459
+
460
+ it '#verify_witness_input_signature' do
461
+ #P2WPKH
462
+ tx = Tx.new('01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000'.htb)
463
+ tx.verify_witness_input_signature(1, '00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'.htb, 600000000).should == true
464
+
465
+ # P2WSH
466
+ tx = Tx.new('01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000'.htb)
467
+ tx.verify_witness_input_signature(1, '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'.htb, 4900000000).should == true
468
+
469
+ # P2SH-P2WPKH
470
+ tx = Bitcoin::P::Tx.new('01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000'.htb)
471
+ tx.verify_witness_input_signature(0, 'a9144733f37cf4db86fbc2efed2500b4f4e49f31202387'.htb, 1000000000).should == true
472
+
473
+ # P2SH-P2WSH
474
+ tx = Bitcoin::P::Tx.new('0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000'.htb)
475
+ tx.verify_witness_input_signature(0, 'a9149993a429037b5d912407a71c252019287b8d27a587'.htb, 987654321).should == true
476
+ end
477
+
478
+ describe '#signature_hash_for_input' do
479
+ it 'sighash_all' do
480
+ prev_tx = Tx.new( fixtures_file('rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin') )
481
+ prev_tx.hash.should == "2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a"
482
+
483
+ key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
484
+ pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
485
+ new_tx = Tx.new(nil)
486
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
487
+ new_tx.add_out( TxOut.value_to_address(1000000, "1BVJWLTCtjA8wRivvrCiwjNdL6KjdMUCTZ") )
488
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
489
+ sig = Bitcoin.sign_data(key, signature_hash)
490
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
491
+
492
+ new_tx = Tx.new( new_tx.to_payload )
493
+ new_tx.hash.should != nil
494
+ new_tx.verify_input_signature(0, prev_tx).should == true
495
+
496
+
497
+
498
+ prev_tx = Tx.new( fixtures_file('rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin') )
499
+ prev_tx.hash.should == "14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984"
500
+
501
+ key = Bitcoin.open_key("115ceda6c1e02d41ce65c35a30e82fb325fe3f815898a09e1a5d28bb1cc92c6e",
502
+ pubkey="0409d103127d26ce93ee41f1b9b1ed4c1c243acf48e31eb5c4d88ad0342ccc010a1a8d838846cf7337f2b44bc73986c0a3cb0568fa93d068b2c8296ce8d47b1545")
503
+ new_tx = Tx.new(nil)
504
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
505
+ pk_script = Bitcoin::Script.to_address_script("1FEYAh1x5jeKQMPPuv3bKnKvbgVAqXvqjW")
506
+ new_tx.add_out( TxOut.new(1000000, pk_script) )
507
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
508
+ sig = Bitcoin.sign_data(key, signature_hash)
509
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
510
+
511
+ new_tx = Tx.new( new_tx.to_payload )
512
+ new_tx.hash.should != nil
513
+ new_tx.verify_input_signature(0, prev_tx).should == true
514
+
515
+
516
+
517
+ prev_tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
518
+ prev_tx.hash.should == "b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d"
519
+
520
+ key = Bitcoin.open_key("56e28a425a7b588973b5db962a09b1aca7bdc4a7268cdd671d03c52a997255dc",
521
+ pubkey="04324c6ebdcf079db6c9209a6b715b955622561262cde13a8a1df8ae0ef030eaa1552e31f8be90c385e27883a9d82780283d19507d7fa2e1e71a1d11bc3a52caf3")
522
+ new_tx = Tx.new(nil)
523
+ new_tx.add_in( TxIn.new(prev_tx.binary_hash, 0, 0) )
524
+ new_tx.add_out( TxOut.value_to_address(1000000, "14yz7fob6Q16hZu4nXfmv1kRJpSYaFtet5") )
525
+ signature_hash = new_tx.signature_hash_for_input(0, prev_tx)
526
+ sig = Bitcoin.sign_data(key, signature_hash)
527
+ new_tx.in[0].script_sig = Bitcoin::Script.to_pubkey_script_sig(sig, [pubkey].pack("H*"))
528
+
529
+ new_tx = Tx.new( new_tx.to_payload )
530
+ new_tx.hash.should != nil
531
+ new_tx.verify_input_signature(0, prev_tx).should == true
532
+ end
533
+
534
+ it 'sighash JSON tests' do
535
+ test_cases = JSON.parse(fixtures_file('sighash.json'))
536
+ test_cases.each do |test_case|
537
+ # Single element arrays in tests are comments.
538
+ next if test_case.length == 1
539
+
540
+ transaction = Bitcoin::Protocol::Tx.new(test_case[0].htb)
541
+ subscript = test_case[1].htb
542
+ input_index = test_case[2].to_i
543
+ hash_type = test_case[3]
544
+ amount = 0
545
+ expected_sighash = test_case[4].htb_reverse
546
+
547
+ actual_sighash = transaction.signature_hash_for_input(
548
+ input_index, subscript, hash_type, amount, 0)
549
+ actual_sighash.should == expected_sighash
550
+ end
551
+ end
552
+ end
553
+
554
+ it '#signature_hash_for_witness_input' do
555
+ # P2WPKH https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#Native_P2WPKH
556
+ tx = Tx.new('0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000'.htb)
557
+ signature_hash = tx.signature_hash_for_witness_input(1, '00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'.htb, 600000000)
558
+ signature_hash.bth.should == 'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670'
559
+
560
+ # P2WSH https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#Native_P2WSH
561
+ tx = Tx.new('0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000'.htb)
562
+ script_pubkey = '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'
563
+ witness_script = '21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac'
564
+ signature_hash = tx.signature_hash_for_witness_input(1, script_pubkey.htb, 4900000000, witness_script.htb, Tx::SIGHASH_TYPE[:single])
565
+ signature_hash.bth.should == '82dde6e4f1e94d02c2b7ad03d2115d691f48d064e9d52f58194a6637e4194391'
566
+
567
+ # P2WSH with invalid witness script
568
+ tx = Tx.new('0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000'.htb)
569
+ script_pubkey = '00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0'
570
+ witness_script = 'AAA'
571
+ proc{
572
+ tx.signature_hash_for_witness_input(1, script_pubkey.htb, 4900000000, witness_script.htb)
573
+ }.should.raise Exception
574
+ end
575
+
576
+ it "#legacy_sigops_count" do
577
+ Tx.new(@payload[0]).legacy_sigops_count.should == 2
578
+ Tx.new(@payload[1]).legacy_sigops_count.should == 2
579
+ Tx.new(@payload[2]).legacy_sigops_count.should == 2
580
+
581
+ # Test sig ops count in inputs too.
582
+ tx = Tx.new
583
+ txin = TxIn.new
584
+ txin.script_sig = Bitcoin::Script.from_string("10 OP_CHECKMULTISIGVERIFY OP_CHECKSIGVERIFY").to_binary
585
+ tx.add_in(txin)
586
+ txout = TxOut.new
587
+ txout.pk_script = Bitcoin::Script.from_string("5 OP_CHECKMULTISIG OP_CHECKSIG").to_binary
588
+ tx.add_out(txout)
589
+ tx.legacy_sigops_count.should == (20 + 1 + 20 + 1)
590
+
591
+ end
592
+
593
+ describe "Tx - is_final?" do
594
+ it "should be final if lock_time == 0" do
595
+ tx = Tx.new
596
+ tx.lock_time = 0
597
+ tx.is_final?(0,0).should == true
598
+
599
+ # even if has non-final input:
600
+ txin = TxIn.new
601
+ txin.sequence = "\x01\x00\x00\x00"
602
+ tx.add_in(txin)
603
+ tx.is_final?(0,0).should == true
604
+ end
605
+
606
+ it "should be final if lock_time is below block_height" do
607
+ tx = Tx.new
608
+ txin = TxIn.new
609
+ txin.sequence = "\x01\x00\x00\x00"
610
+ tx.add_in(txin)
611
+ tx.lock_time = 6543
612
+ tx.is_final?(6000,0).should == false
613
+ tx.is_final?(6543,0).should == false # when equal to block height, still not final
614
+ tx.is_final?(6544,0).should == true
615
+ tx.is_final?(9999,0).should == true
616
+ end
617
+
618
+ it "should be final if lock_time is below timestamp" do
619
+ tx = Tx.new
620
+ txin = TxIn.new
621
+ txin.sequence = "\xff\xff\xff\xff"
622
+ tx.add_in(txin)
623
+ txin = TxIn.new
624
+ txin.sequence = "\x01\x00\x00\x00"
625
+ tx.add_in(txin)
626
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD # when equal, interpreted as threshold
627
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == false
628
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == false # when equal to timestamp, still not final
629
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
630
+
631
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
632
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == false
633
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == false # when equal to timestamp, still not final
634
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
635
+ end
636
+
637
+ it "should be final if all inputs are finalized regardless of lock_time" do
638
+ tx = Tx.new
639
+ txin = TxIn.new
640
+ txin.sequence = "\xff\xff\xff\xff"
641
+ tx.add_in(txin)
642
+ txin = TxIn.new
643
+ txin.sequence = "\xff\xff\xff\xff"
644
+ tx.add_in(txin)
645
+
646
+ tx.lock_time = 6543
647
+ tx.is_final?(6000,0).should == true
648
+ tx.is_final?(6543,0).should == true
649
+ tx.is_final?(6544,0).should == true
650
+ tx.is_final?(9999,0).should == true
651
+
652
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD
653
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == true
654
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == true
655
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
656
+
657
+ tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
658
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
659
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == true
660
+ tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
661
+ end
662
+
663
+ end
664
+
665
+ it '#calculate_minimum_fee' do
666
+ tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
667
+ tx.minimum_relay_fee.should == 0
668
+ tx.minimum_block_fee.should == 0
669
+ tx = Tx.from_json(fixtures_file('bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json'))
670
+ tx.minimum_relay_fee.should == 0
671
+ tx.minimum_block_fee.should == 10_000
672
+ end
673
+
674
+ it '#calculate_minimum_fee for litecoin' do
675
+ tx = Tx.from_json(fixtures_file('litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json'))
676
+ tx.minimum_relay_fee.should == 0
677
+ tx.minimum_block_fee.should == 30_000
678
+ Bitcoin.network = :litecoin # change to litecoin
679
+ tx.minimum_relay_fee.should == 0
680
+ tx.minimum_block_fee.should == 100_000
681
+ end
682
+
683
+ it "should compare transactions" do
684
+ tx1 = Tx.new( @payload[0] )
685
+ tx2 = Tx.new( @payload[1] )
686
+ (tx1 == Bitcoin::P::Tx.from_json(tx1.to_json)).should == true
687
+ (tx1 == tx2).should == false
688
+ (tx1 == nil).should == false
689
+ end
690
+
691
+ describe "Tx - BIP Scripts" do
692
+
693
+ it "should do OP_CHECKMULTISIG" do
694
+ # checkmultisig without checkhashverify
695
+ tx = Tx.from_json(fixtures_file('23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json'))
696
+ prev_tx = Tx.from_json(fixtures_file('60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json'))
697
+ tx.verify_input_signature(0, prev_tx).should == true
698
+
699
+ # p2sh + multisig transaction from mainnet
700
+ tx = Tx.from_json( fixtures_file('rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json') )
701
+ prev_tx = Tx.from_json( fixtures_file("rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json") )
702
+ tx.verify_input_signature(0, prev_tx).should == true
703
+
704
+ # checkmultisig for testnet3 tx: 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1 input index 1
705
+ tx = Tx.from_json( fixtures_file('tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json') )
706
+ prev_tx = Tx.from_json( fixtures_file("tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json") )
707
+ tx.verify_input_signature(1, prev_tx).should == true
708
+ end
709
+
710
+ it "should do P2SH with inner OP_CHECKMULTISIG (BIP 0016)" do
711
+ tx = Tx.from_json(fixtures_file('3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json'))
712
+ prev_tx = Tx.from_json(fixtures_file('35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json'))
713
+ tx.verify_input_signature(0, prev_tx).should == true
714
+
715
+ tx = Tx.from_json(fixtures_file('bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json'))
716
+ prev_tx = Tx.from_json(fixtures_file('ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json'))
717
+ tx.verify_input_signature(1, prev_tx).should == true
718
+
719
+ # p2sh transaction with non-standard OP_CHECKMULTISIG inside found in testnet3 tx: d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830
720
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json'))
721
+ tx.hash.should == "d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830"
722
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json'))
723
+ prev_tx.hash.should == "313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0"
724
+ tx.verify_input_signature(0, prev_tx).should == true
725
+ end
726
+
727
+ it "should do P2SH with inner OP_CHECKSIG" do
728
+ # p2sh transaction with non-standard OP_CHECKSIG inside found in testnet3 tx: 3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae
729
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json'))
730
+ tx.hash.should == "3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae"
731
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json'))
732
+ prev_tx.hash.should == "44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a"
733
+ tx.verify_input_signature(0, prev_tx).should == true
734
+ end
735
+
736
+ it "should do OP_CHECKMULTISIG with OP_0 used as a pubkey" do
737
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json'))
738
+ tx.hash.should == "6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba"
739
+ prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json'))
740
+ prev_tx.hash.should == "4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9"
741
+ tx.verify_input_signature(0, prev_tx).should == true
742
+ end
743
+
744
+ end
745
+
746
+ it 'lexicographical_sort' do
747
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json'))
748
+ tx.hash.should == '0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3'
749
+ tx.lexicographical_sort!
750
+ tx.in[0].previous_output.should == '0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57'
751
+ tx.in[1].previous_output.should == '26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024'
752
+ tx.in[2].previous_output.should == '28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2'
753
+ tx.in[3].previous_output.should == '381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d'
754
+ tx.in[4].previous_output.should == '3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2'
755
+ tx.in[5].previous_output.should == '402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a'
756
+ tx.in[6].previous_output.should == '54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a'
757
+ tx.in[7].previous_output.should == '643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa'
758
+ tx.in[8].previous_output.should == '6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1'
759
+ tx.in[9].previous_output.should == '7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191'
760
+ tx.in[10].previous_output.should == '7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4'
761
+ tx.in[11].previous_output.should == 'a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086'
762
+ tx.in[12].previous_output.should == 'b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8'
763
+ tx.in[13].previous_output.should == 'bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85'
764
+ tx.in[14].previous_output.should == 'de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9'
765
+ tx.in[15].previous_output.should == 'f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45'
766
+ tx.in[16].previous_output.should == 'f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60'
767
+ tx.out[0].value.should == 400057456
768
+ tx.out[1].value.should == 40000000000
769
+
770
+ tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json'))
771
+ tx.hash.should == '28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f'
772
+ tx.lexicographical_sort!
773
+ tx.in[0].previous_output.should == '35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055'
774
+ tx.in[0].prev_out_index.should == 0
775
+ tx.in[1].previous_output.should == '35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055'
776
+ tx.in[1].prev_out_index.should == 1
777
+ tx.out[0].value.should == 100000000
778
+ tx.out[1].value.should == 2400000000
779
+
780
+ tx = Bitcoin::P::Tx.new
781
+ tx.add_out(Bitcoin::P::TxOut.new(500, 'bbbbbbbb'.htb))
782
+ tx.add_out(Bitcoin::P::TxOut.new(500, 'aaaaaaaa'.htb))
783
+ tx.add_out(Bitcoin::P::TxOut.new(500, 'cccccccc'.htb))
784
+ tx.lexicographical_sort!
785
+ tx.out[0].pk_script.bth.should == 'aaaaaaaa'
786
+ tx.out[1].pk_script.bth.should == 'bbbbbbbb'
787
+ tx.out[2].pk_script.bth.should == 'cccccccc'
788
+ end
789
+
790
+ describe 'verify_input_signature' do
791
+ def parse_script(script_str)
792
+ script = Bitcoin::Script.new('')
793
+
794
+ buf = ""
795
+ script_str.split.each do |token|
796
+ opcode = Bitcoin::Script::OPCODES_PARSE_STRING[token] ||
797
+ Bitcoin::Script::OPCODES_PARSE_STRING['OP_' + token]
798
+ if opcode
799
+ buf << [opcode].pack('C')
800
+ next
801
+ end
802
+
803
+ data =
804
+ case token
805
+ when /\A-?\d+\z/
806
+ i = token.to_i
807
+ opcode =
808
+ case i
809
+ when -1 then Bitcoin::Script::OP_1NEGATE
810
+ when 0 then Bitcoin::Script::OP_0
811
+ when 1 then Bitcoin::Script::OP_1
812
+ when 2..16 then Bitcoin::Script::OP_2 + i - 2
813
+ end
814
+
815
+ if opcode
816
+ [opcode].pack('C')
817
+ else
818
+ Bitcoin::Script.pack_pushdata(script.cast_to_string(i))
819
+ end
820
+ when /\A'(.*)'\z/ then Bitcoin::Script.pack_pushdata($1)
821
+ when /\A0x([0-9a-fA-F]+)\z/ then $1.htb
822
+ else raise "Unexpected token #{token}"
823
+ end
824
+ buf << data
825
+ end
826
+ buf
827
+ end
828
+
829
+ def parse_flags(flags_str)
830
+ flags_str.split(',').each_with_object({}) do |flag_str, opts|
831
+ case flag_str.to_sym
832
+ when :STRICTENC then opts[:verify_strictenc] = true
833
+ when :DERSIG then opts[:verify_dersig] = true
834
+ when :LOW_S then opts[:verify_low_s] = true
835
+ when :SIGPUSHONLY then opts[:verify_sigpushonly] = true
836
+ when :MINIMALDATA then opts[:verify_minimaldata] = true
837
+ when :CLEANSTACK then opts[:verify_cleanstack] = true
838
+ when :SIGHASH_FORKID then opts[:fork_id] = 0
839
+ end
840
+ end
841
+ end
842
+
843
+ it 'script JSON tests' do
844
+ test_cases = JSON.parse(fixtures_file('script_tests.json'))
845
+ test_cases.each_with_index do |test_case, i|
846
+ # Single element arrays in tests are comments.
847
+ next if test_case.length == 1
848
+
849
+ value =
850
+ if test_case[0].is_a?(Array)
851
+ (test_case.shift[0] * 10**8).to_i
852
+ else
853
+ 0
854
+ end
855
+
856
+ # TODO: Implement these opcodes correctly
857
+ next if test_case[0].match(/CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/)
858
+ next if test_case[1].match(/CHECKLOCKTIMEVERIFY|CHECKSEQUENCEVERIFY|RESERVED|0x50|VERIF|VERNOTIF/)
859
+
860
+ script_sig = parse_script(test_case[0])
861
+ script_pubkey = parse_script(test_case[1])
862
+ opts = parse_flags(test_case[2])
863
+ expect_success = test_case[3] == 'OK'
864
+
865
+ # A lot of the test cases are failing, so for now we only test the SIGHASH_FORKID ones.
866
+ # TODO: Get this spec passing without this line.
867
+ next unless opts[:fork_id]
868
+
869
+ crediting_tx = Tx.new
870
+ crediting_tx.add_in(TxIn.new)
871
+ crediting_tx.in[0].prev_out_hash = TxIn::NULL_HASH
872
+ crediting_tx.in[0].prev_out_index = TxIn::COINBASE_INDEX
873
+ crediting_tx.in[0].script_sig = parse_script('0 0')
874
+ crediting_tx.add_out(TxOut.new)
875
+ crediting_tx.out[0].value = value
876
+ crediting_tx.out[0].pk_script = script_pubkey
877
+ crediting_tx.refresh_hash
878
+
879
+ spending_tx = Tx.new
880
+ spending_tx.add_in(TxIn.new)
881
+ spending_tx.in[0].prev_out_hash = crediting_tx.binary_hash
882
+ spending_tx.in[0].prev_out_index = 0
883
+ spending_tx.in[0].script_sig = script_sig
884
+ spending_tx.add_out(TxOut.new)
885
+ spending_tx.out[0].value = value
886
+ spending_tx.out[0].pk_script = ''
887
+ spending_tx.refresh_hash
888
+
889
+ success = spending_tx.verify_input_signature(0, crediting_tx, Time.now.to_i, opts)
890
+ success.should == expect_success
891
+ end
892
+ end
893
+ end
894
+ end