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,187 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'spec_helper'
5
+
6
+ # rubocop:disable Metrics/LineLength
7
+ describe 'Bitcoin::Bech32' do
8
+ # All test vectors in this file come from BIP-173:
9
+ # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
10
+
11
+ let(:invalid_address_encs) do
12
+ [
13
+ ['BC', 0, 20],
14
+ ['bc', 0, 21],
15
+ ['bc', 17, 32],
16
+ ['bc', 1, 1],
17
+ ['bc', 16, 41]
18
+ ]
19
+ end
20
+ let(:invalid_addresses) do
21
+ %w[
22
+ tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty
23
+ bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5
24
+ BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2
25
+ bc1rw5uspcuh
26
+ bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90
27
+ BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P
28
+ tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7
29
+ bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du
30
+ tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv
31
+ bc1gmk9yu
32
+ ]
33
+ end
34
+ let(:valid_addresses) do
35
+ [
36
+ [
37
+ 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4',
38
+ 22, [
39
+ 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
40
+ 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
41
+ ]
42
+ ],
43
+ [
44
+ 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7',
45
+ 34, [
46
+ 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
47
+ 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
48
+ 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
49
+ 0x62
50
+ ]
51
+ ],
52
+ [
53
+ 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx',
54
+ 42, [
55
+ 0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
56
+ 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
57
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
58
+ 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
59
+ ]
60
+ ],
61
+ [
62
+ 'BC1SW50QA3JX3S',
63
+ 4, [
64
+ 0x60, 0x02, 0x75, 0x1e
65
+ ]
66
+ ],
67
+ [
68
+ 'bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj',
69
+ 18, [
70
+ 0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
71
+ 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23
72
+ ]
73
+ ],
74
+ [
75
+ 'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy',
76
+ 34, [
77
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
78
+ 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
79
+ 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
80
+ 0x33
81
+ ]
82
+ ]
83
+ ]
84
+ end
85
+
86
+ before { Bitcoin.network = :bitcoin }
87
+
88
+ describe '#decode / #encode' do
89
+ context 'test vectors' do
90
+ let(:valid_checksums) do
91
+ %w[
92
+ A12UEL5L
93
+ an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs
94
+ abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw
95
+ 11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j
96
+ split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w
97
+ ]
98
+ end
99
+ let(:invalid_checksums) do
100
+ [
101
+ ' 1nwldj5',
102
+ "\x7f1axkwrx",
103
+ 'an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx',
104
+ 'pzry9x0s0muk',
105
+ '1pzry9x0s0muk',
106
+ 'x1b4n0q5v',
107
+ 'li1dgmt3',
108
+ "de1lg7wt\xff"
109
+ ]
110
+ end
111
+
112
+ it 'works for valid checksums' do
113
+ valid_checksums.each do |encoded_input|
114
+ human_readable_part, data = Bitcoin::Bech32.decode(encoded_input)
115
+ result = Bitcoin::Bech32.encode(human_readable_part, data)
116
+ expect(result).to eq(encoded_input.downcase)
117
+ end
118
+ end
119
+
120
+ it 'returns nil invalid checksums' do
121
+ invalid_checksums.each do |encoded_input|
122
+ human_readable_part, = Bitcoin::Bech32.decode(encoded_input)
123
+ expect(human_readable_part).to be_nil
124
+ end
125
+ end
126
+
127
+ it 'works for valid addresses' do
128
+ valid_addresses.each do |encoded_input, _, _|
129
+ human_readable_part, data = Bitcoin::Bech32.decode(encoded_input)
130
+ result = Bitcoin::Bech32.encode(human_readable_part, data)
131
+ expect(result).to eq(encoded_input.downcase)
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#decode_segwit_address / #encode_segwit_address' do
138
+ context 'test vectors' do
139
+ it 'works for valid addresses' do
140
+ valid_addresses.each do |test_address, _, test_script|
141
+ Bitcoin.network = :bitcoin
142
+ version, program = Bitcoin.decode_segwit_address(test_address)
143
+
144
+ if version.nil?
145
+ Bitcoin.network = :testnet3
146
+ version, program = Bitcoin.decode_segwit_address(test_address)
147
+ end
148
+
149
+ expect(version).not_to be_nil
150
+
151
+ script = Bitcoin::Script.to_witness_script(version, program)
152
+ expect(script).to eq(test_script.pack('C*'))
153
+
154
+ new_address = Bitcoin.encode_segwit_address(version, program)
155
+ expect(new_address).not_to be_nil
156
+ expect(new_address).to eq(test_address.downcase)
157
+ end
158
+ end
159
+
160
+ it 'returns nil for invalid addresses' do
161
+ invalid_addresses.each do |test_address|
162
+ Bitcoin.network = :bitcoin
163
+ version, _program = Bitcoin.decode_segwit_address(test_address)
164
+
165
+ if version.nil?
166
+ Bitcoin.network = :testnet3
167
+ version, _program = Bitcoin.decode_segwit_address(test_address)
168
+ end
169
+
170
+ expect(version).to be_nil
171
+ end
172
+ end
173
+
174
+ it 'returns nil for invalid address encodings' do
175
+ invalid_address_encs.each do |test_hrp, test_version, test_length|
176
+ Bitcoin.network[:bech32_hrp] = test_hrp
177
+ program_hex =
178
+ Array.new(test_length) { 0 }.pack('C*').unpack('H*').first
179
+ new_address = Bitcoin.encode_segwit_address(test_version, program_hex)
180
+
181
+ expect(new_address).to be_nil
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
187
+ # rubocop:enable Metrics/LineLength
@@ -0,0 +1,1079 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pry'
4
+ require 'spec_helper'
5
+
6
+ describe Bitcoin do
7
+ before { Bitcoin.network = :bitcoin }
8
+
9
+ describe '.hash160' do
10
+ it 'produces the expected public key hash' do
11
+ # 65 bytes (8 bit version + 512 bits) pubkey in hex (130 bytes)
12
+ pubkey = '04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f6' \
13
+ '1deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b' \
14
+ '6bf11d5f'
15
+
16
+ expect(Bitcoin.hash160(pubkey))
17
+ .to eq('62e907b15cbf27d5425399ebf6f0fb50ebb88f18')
18
+ end
19
+ end
20
+
21
+ describe '.hash160_to_address' do
22
+ let(:pubkey_hash) { '62e907b15cbf27d5425399ebf6f0fb50ebb88f18' }
23
+
24
+ context 'testnet' do
25
+ before { Bitcoin.network = :testnet }
26
+
27
+ it 'produces the expected address' do
28
+ expect(Bitcoin.hash160_to_address(pubkey_hash))
29
+ .to eq('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
30
+ end
31
+ end
32
+
33
+ context 'mainnet' do
34
+ before { Bitcoin.network = :bitcoin }
35
+
36
+ it 'produces the expected address' do
37
+ expect(Bitcoin.hash160_to_address(pubkey_hash))
38
+ .to eq('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '.pubkey_to_address' do
44
+ let(:compressed_pubkey) do
45
+ '029e31ccb7308c2525d542024b8119a3ab3767933e82aedd1471f9c714d998d1b4'
46
+ end
47
+ let(:uncompressed_pubkey) do
48
+ '049e31ccb7308c2525d542024b8119a3ab3767933e82aedd1471f9c714d998d1b4b823' \
49
+ '14814017e4e9b06a0fd8e01772bb410cb1c36cfc2d03079c315bc7494b86'
50
+ end
51
+
52
+ context 'testnet' do
53
+ before { Bitcoin.network = :testnet }
54
+
55
+ it 'works for compressed pubkey' do
56
+ expect(Bitcoin.pubkey_to_address(compressed_pubkey))
57
+ .to eq('mu6vSuyvpVxvDAJyZczjxaU56pXLNBSf9C')
58
+ end
59
+
60
+ it 'works for uncompressed pubkey' do
61
+ expect(Bitcoin.pubkey_to_address(uncompressed_pubkey))
62
+ .to eq('n4bZ82i9SdLj6YauPn3PPKFRhQHMZrdaPq')
63
+ end
64
+ end
65
+
66
+ context 'mainnet' do
67
+ before { Bitcoin.network = :bitcoin }
68
+
69
+ it 'works for compressed pubkey' do
70
+ expect(Bitcoin.pubkey_to_address(compressed_pubkey))
71
+ .to eq('1Eay9rtx1UXfS3qMr42N8fFkEpvdR2euvg')
72
+ end
73
+
74
+ it 'works for uncompressed pubkey' do
75
+ expect(Bitcoin.pubkey_to_address(uncompressed_pubkey))
76
+ .to eq('1Q5bpydAdbuUKS7HgD51ZQ36qQgeiN8cBE')
77
+ end
78
+ end
79
+ end
80
+
81
+ describe '.pubkeys_to_p2sh_multisig_address' do
82
+ let(:pubkey1) do
83
+ '029e31ccb7308c2525d542024b8119a3ab3767933e82aedd1471f9c714d998d1b4'
84
+ end
85
+ let(:pubkey2) do
86
+ '0299acf23a65c31fe02052d7474769529c21612b1afa56cc149747fe63867592ec'
87
+ end
88
+ let(:pubkey3) do
89
+ '020b16a7227f873ac68cf3140f1101d2eda5acb28bf3e7d546409139caf25142e4'
90
+ end
91
+
92
+ context 'testnet' do
93
+ before { Bitcoin.network = :testnet }
94
+
95
+ it 'produces the expected address and redeem script' do
96
+ address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(
97
+ 2, pubkey1, pubkey2
98
+ )
99
+
100
+ expect(address).to eq('2NGaiH7MNYWhsWPQKudZEvy8KnoWPfuGPg1')
101
+ expect(redeem_script.hth)
102
+ .to eq('52' + # OP_2
103
+ '21' + pubkey1 + # pubkey1.bytesize + pubkey1
104
+ '21' + pubkey2 + # pubkey2.bytesize + pubkey2
105
+ '52' + # OP_2
106
+ 'ae') # OP_CHECKMULTISIG
107
+ end
108
+ end
109
+
110
+ context 'mainnet' do
111
+ before { Bitcoin.network = :bitcoin }
112
+
113
+ it 'produces the expected address and redeem script' do
114
+ address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(
115
+ 2, pubkey1, pubkey2, pubkey3
116
+ )
117
+ expect(address).to eq('38eiL6Jac27TVAu83wj81Miso9rXiVqgcP')
118
+ expect(redeem_script.hth)
119
+ .to eq('52' + # OP_2
120
+ '21' + pubkey1 + # pubkey1.bytesize + pubkey1
121
+ '21' + pubkey2 + # pubkey2.bytesize + pubkey2
122
+ '21' + pubkey3 + # pubkey3.bytesize + pubkey3
123
+ '53' + # OP_3
124
+ 'ae') # OP_CHECKMULTISIG
125
+ end
126
+ end
127
+ end
128
+
129
+ describe '.hash160_from_address' do
130
+ let(:pubkey_hash_hex) { '62e907b15cbf27d5425399ebf6f0fb50ebb88f18' }
131
+
132
+ context 'testnet' do
133
+ before { Bitcoin.network = :testnet }
134
+
135
+ it 'produces the expected hash' do
136
+ expect(
137
+ Bitcoin.hash160_from_address('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
138
+ ).to eq('62e907b15cbf27d5425399ebf6f0fb50ebb88f18')
139
+ end
140
+
141
+ it 'returns nil for invalid address' do
142
+ expect(Bitcoin.hash160_from_address('bad-address-testnet')).to be_nil
143
+ end
144
+
145
+ it 'survives rounds of conversion from hash160 to address' do
146
+ addr = 'mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt'
147
+
148
+ expect(
149
+ Bitcoin.hash160_from_address(
150
+ Bitcoin.hash160_to_address(pubkey_hash_hex)
151
+ )
152
+ ).to eq(pubkey_hash_hex)
153
+
154
+ expect(
155
+ Bitcoin.hash160_to_address(
156
+ Bitcoin.hash160_from_address(addr)
157
+ )
158
+ ).to eq(addr)
159
+ end
160
+ end
161
+
162
+ context 'mainnet' do
163
+ before { Bitcoin.network = :bitcoin }
164
+
165
+ it 'returns expected values for addresses' do
166
+ expect(
167
+ Bitcoin.hash160_from_address('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')
168
+ ).to eq('62e907b15cbf27d5425399ebf6f0fb50ebb88f18')
169
+ expect(
170
+ Bitcoin.hash160_from_address('11ofrrzv87Ls97jN4TUetfQp4gEsUSL7A')
171
+ ).to eq('0026f5494b39ea04b7bcb05e583acf3b0102d61f')
172
+ expect(
173
+ Bitcoin.hash160_from_address('11122RGUQSszAsTpptd2h8sdyYGR6nKs6f')
174
+ ).to eq('0000daec8d6f05e949710f202c4f73258aa7791e')
175
+ expect(
176
+ Bitcoin.hash160_from_address('11119uLoMQCBHmKevdsFKHMaUoyrwLa9Y')
177
+ ).to eq('00000090c66372823859c935149e2e32d276a1e6')
178
+ expect(
179
+ Bitcoin.hash160_from_address('1111136sgL8UNSTVL9ize2uGFPxFDGwFp')
180
+ ).to eq('0000000096d3ad65d030a36e2c23f7fdd5dfcadb')
181
+ expect(
182
+ Bitcoin.hash160_from_address(
183
+ 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
184
+ )
185
+ ).to eq('751e76e8199196d454941c45d1b3a323f1433bd6')
186
+ end
187
+
188
+ it 'returns nil for invalid address' do
189
+ expect(Bitcoin.hash160_from_address('bad-address-mainnet')).to be_nil
190
+ end
191
+
192
+ it 'survives rounds of conversion from hash160 to address' do
193
+ addr = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'
194
+
195
+ expect(
196
+ Bitcoin.hash160_from_address(
197
+ Bitcoin.hash160_to_address(pubkey_hash_hex)
198
+ )
199
+ ).to eq(pubkey_hash_hex)
200
+
201
+ expect(
202
+ Bitcoin.hash160_to_address(
203
+ Bitcoin.hash160_from_address(addr)
204
+ )
205
+ ).to eq(addr)
206
+ end
207
+ end
208
+ end
209
+
210
+ describe '.address_checksum?' do
211
+ context 'testnet' do
212
+ before { Bitcoin.network = :testnet }
213
+
214
+ it 'returns true for valid addresses' do
215
+ expect(
216
+ Bitcoin.address_checksum?('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
217
+ ).to be true
218
+ expect(
219
+ Bitcoin.address_checksum?('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW')
220
+ ).to be true
221
+ end
222
+
223
+ it 'returns false for invalid addresses' do
224
+ expect(Bitcoin.address_checksum?('f0f0f0')).to be false
225
+ end
226
+ end
227
+
228
+ context 'mainnet' do
229
+ before { Bitcoin.network = :bitcoin }
230
+
231
+ it 'returns true for valid addresses' do
232
+ expect(
233
+ Bitcoin.address_checksum?('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')
234
+ ).to be true
235
+ expect(
236
+ Bitcoin.address_checksum?('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
237
+ ).to be true
238
+ end
239
+
240
+ it 'returns false for invalid addresses' do
241
+ expect(Bitcoin.address_checksum?('f0f0f0')).to be false
242
+ end
243
+ end
244
+ end
245
+
246
+ describe '.valid_address?' do
247
+ context 'testnet' do
248
+ before { Bitcoin.network = :testnet }
249
+
250
+ it 'is true for valid addresses' do
251
+ expect(
252
+ Bitcoin.valid_address?('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
253
+ ).to be true
254
+ end
255
+
256
+ it 'is false for invalid addresses' do
257
+ expect(
258
+ Bitcoin.valid_address?('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW')
259
+ ).to be false
260
+ expect(
261
+ Bitcoin.valid_address?('1moYFpRM4LkTV4Ho5eCxiEPB2bSm3AsJNGj')
262
+ ).to be false
263
+ expect(Bitcoin.valid_address?('f0f0f0')).to be false
264
+ end
265
+
266
+ it 'successfully validates a series of new addresses' do
267
+ 400.times do
268
+ addr = Bitcoin.generate_address
269
+ expect(Bitcoin.hash160_from_address(addr[0])).to eq(addr[-1])
270
+ expect(Bitcoin.hash160_to_address(addr[-1])).to eq(addr[0])
271
+ expect(Bitcoin.valid_address?(addr[0])).to be true
272
+ end
273
+ end
274
+
275
+ it 'validates p2sh address' do
276
+ expect(
277
+ Bitcoin.valid_address?('2MyLngQnhzjzatKsB7XfHYoP9e2XUXSiBMM')
278
+ ).to be true
279
+ end
280
+ end
281
+
282
+ context 'mainnet' do
283
+ before { Bitcoin.network = :bitcoin }
284
+
285
+ it 'is true for valid addresses' do
286
+ expect(
287
+ Bitcoin.valid_address?('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW')
288
+ ).to be true
289
+ expect(
290
+ Bitcoin.valid_address?('1ZQxJYBRmbb2rDNYPhd96x3eMbNnPD98q')
291
+ ).to be true
292
+ expect(
293
+ Bitcoin.valid_address?('12KhCL8nGK3Luy7ehU3AxPs1mTocdessLM')
294
+ ).to be true
295
+ expect(
296
+ Bitcoin.valid_address?('1AnNQgfaGgSKejzR6km74tyQPDGwZBBVT')
297
+ ).to be true
298
+ end
299
+
300
+ it 'is false for invalid addresses' do
301
+ expect(
302
+ Bitcoin.valid_address?('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt')
303
+ ).to be false
304
+ expect(
305
+ Bitcoin.valid_address?('2D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW')
306
+ ).to be false
307
+ expect(
308
+ Bitcoin.valid_address?('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cX')
309
+ ).to be false
310
+ expect(
311
+ Bitcoin.valid_address?('1moYFpRM4LkTV4Ho5eCxiEPB2bSm3AsJNGj')
312
+ ).to be false
313
+ expect(
314
+ Bitcoin.valid_address?('f0f0f0')
315
+ ).to be false
316
+ end
317
+
318
+ it 'successfully validates a series of new addresses' do
319
+ 400.times do
320
+ addr = Bitcoin.generate_address
321
+ expect(Bitcoin.hash160_from_address(addr[0])).to eq(addr[-1])
322
+ expect(Bitcoin.hash160_to_address(addr[-1])).to eq(addr[0])
323
+ expect(Bitcoin.valid_address?(addr[0])).to be true
324
+ end
325
+ end
326
+
327
+ it 'validates p2sh address' do
328
+ expect(
329
+ Bitcoin.valid_address?('3CkxTG25waxsmd13FFgRChPuGYba3ar36B')
330
+ ).to be true
331
+ end
332
+ end
333
+ end
334
+
335
+ describe '.base58_to_int' do
336
+ it 'returns the expected integer equivalent' do
337
+ expect(
338
+ Bitcoin.base58_to_int('114EpVhtPpJQKti8HiH2fvXZFPiPkgDZrE')
339
+ ).to eq(
340
+ 15_016_857_106_811_133_404_017_207_799_481_956_647_721_349_092_596_212_439
341
+ )
342
+ end
343
+ end
344
+
345
+ describe '.valid_pubkey?' do
346
+ let(:key) { Bitcoin::Key.generate }
347
+
348
+ it 'is true for compressed and uncompressed keys' do
349
+ expect(Bitcoin.valid_pubkey?(key.pub_compressed)).to be true
350
+ expect(Bitcoin.valid_pubkey?(key.pub_uncompressed)).to be true
351
+ end
352
+
353
+ it 'is false for invalid public keys' do
354
+ expect(Bitcoin.valid_pubkey?(key.addr)).to be false
355
+ expect(Bitcoin.valid_pubkey?(key.priv)).to be false
356
+ end
357
+ end
358
+
359
+ describe '.address_type' do
360
+ context 'testnet' do
361
+ before { Bitcoin.network = :testnet }
362
+
363
+ it 'works for a p2sh address' do
364
+ expect(Bitcoin.address_type('2MyLngQnhzjzatKsB7XfHYoP9e2XUXSiBMM'))
365
+ .to eq(:p2sh)
366
+ end
367
+
368
+ it 'works for a hash160 address' do
369
+ expect(Bitcoin.address_type('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt'))
370
+ .to eq(:hash160)
371
+ end
372
+
373
+ it 'is nil for an invalid address' do
374
+ expect(Bitcoin.address_type('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW'))
375
+ .to be_nil
376
+ end
377
+ end
378
+
379
+ context 'mainnet' do
380
+ before { Bitcoin.network = :bitcoin }
381
+
382
+ it 'works for a p2sh address' do
383
+ expect(Bitcoin.address_type('3CkxTG25waxsmd13FFgRChPuGYba3ar36B'))
384
+ .to eq(:p2sh)
385
+ end
386
+
387
+ it 'works for a hash160 address' do
388
+ expect(Bitcoin.address_type('1D3KpY5kXnYhTbdCbZ9kXb2ZY7ZapD85cW'))
389
+ .to eq(:hash160)
390
+ end
391
+
392
+ it 'works for a witness_v0_keyhash address' do
393
+ expect(Bitcoin.address_type('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'))
394
+ .to eq(:witness_v0_keyhash)
395
+ end
396
+
397
+ it 'works for a witness_v0_scripthash address' do
398
+ expect(
399
+ Bitcoin.address_type('bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3')
400
+ ).to eq(:witness_v0_scripthash)
401
+ end
402
+
403
+ it 'is nil for invalid addresses' do
404
+ expect(Bitcoin.address_type('bc1qw508d6qejxtdg4y5r3zarvayr0c5xw7kv8f3t4'))
405
+ .to be_nil
406
+ expect(Bitcoin.address_type('mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt'))
407
+ .to be_nil
408
+ end
409
+ end
410
+
411
+ context 'litecoin' do
412
+ before { Bitcoin.network = :litecoin }
413
+
414
+ it 'works for p2sh addresses' do
415
+ expect(
416
+ Bitcoin.address_type('3CkxTG25waxsmd13FFgRChPuGYba3ar36B')
417
+ ).to eq(:p2sh)
418
+ expect(
419
+ Bitcoin.address_type('MJy6m9S3thpJa8GwM8fm2LeJbFC22w18Vx')
420
+ ).to eq(:p2sh)
421
+ end
422
+
423
+ it 'is nil for invalid addresses' do
424
+ expect(
425
+ Bitcoin.address_type('2MyLngQnhzjzatKsB7XfHYoP9e2XUXSiBMM')
426
+ ).to be_nil
427
+ end
428
+ end
429
+
430
+ context 'zcash' do
431
+ before {
432
+ Bitcoin::NETWORKS[:zcash] = Bitcoin::NETWORKS[:bitcoin].merge(
433
+ project: :zcash,
434
+ address_version: '1cb8',
435
+ p2sh_version: '1cbd',
436
+ )
437
+ Bitcoin.network = :zcash
438
+ }
439
+
440
+ it 'works for a hash160 address' do
441
+ expect(Bitcoin.address_type('t1KBT8oCGAfisNNWnSD3h7TSsZ7qKah935g'))
442
+ .to eq(:hash160)
443
+ end
444
+
445
+ it 'is nil for invalid addresses' do
446
+ expect(
447
+ Bitcoin.address_type('2MyLngQnhzjzatKsB7XfHYoP9e2XUXSiBMM')
448
+ ).to be_nil
449
+ end
450
+ end
451
+ end
452
+
453
+ describe '.checksum' do
454
+ it 'produces the expected checksum' do
455
+ expect(
456
+ Bitcoin.checksum('0062e907b15cbf27d5425399ebf6f0fb50ebb88f18')
457
+ ).to eq('c29b7d93')
458
+ end
459
+ end
460
+
461
+ describe '.bitcoin_mrkl / .bitcoin_hash' do
462
+ # block 170 is the first block that has a transaction.
463
+ # hash 00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee
464
+ let(:a) { 'b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082' }
465
+ let(:b) { 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16' }
466
+ let(:c) { '7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff' }
467
+
468
+ it 'produces the expected values' do
469
+ expect(Bitcoin.bitcoin_hash(b + a)).to eq(c)
470
+ expect(Bitcoin.bitcoin_mrkl(a, b)).to eq(c)
471
+ end
472
+ end
473
+
474
+ describe 'merkle trees' do
475
+ let(:merkle_tree1) do
476
+ # mrkl tree for block 170
477
+ %w[
478
+ b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082
479
+ f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16
480
+ 7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff
481
+ ]
482
+ end
483
+ let(:merkle_tree2) do
484
+ %w[
485
+ 4fa598026d9be1ca0c2bff1b531e566b7ea7f90b72e75fda0c1795bc2dfa375c
486
+ 186640daf908156e2616790d7c816235b0c43f668c3c38351b348c08ca44d457
487
+ ef3928700309b4deceac9a992a19a7481b4e520cbc0b1ab74e2645eee39c8da0
488
+ 688c53517f62f7a65c0e87519c18a4de98f2ccafbf389b269d0bb867f88d166a
489
+ 01889506f7fe9210045f588361881e2d16a034a62bc48ebd7b6b0a3edeaf5a6d
490
+ 74f3a7df861d6a58957b84a3e425a8cf57e1e2e3a3def046dd200baeb8714f00
491
+ ]
492
+ end
493
+ let(:merkle_tree3) do
494
+ %w[
495
+ 349f717b6630e1f305f95964a2d94117dacca76e0b715d4d7a5657698ec96c6c
496
+ 7f44a84349200473455bcfc05ee68036e23993a6f58dce3f6a7faab46a754440
497
+ 6b3ba3fdfb7eeb6c2e5fd0e36e5bb4634da294521f7b1b808286c214981f9b17
498
+ 0467b41043d654ba3dc3940cbefec0eb38feed6e7085a8e825e4f782eccb48e3
499
+ 83d0231624f7a7d5c37557461ac0d09a8ad7a1f4ab673dd697acb275d4b114de
500
+ 074970aaa98db7d00e6f97a719fe85e9c7f51b75fa5a9a92218d568ccc2b21fe
501
+ c1b6d2a416de6b63e42c1b50f229911bfb07f816e0795bb86ff7dcf0463ab0df
502
+ 751bcfd8acc10792f42050dca5b852f7a2fcd5300897d05907a98473f59a5650
503
+ 7abf551000d942efb93afc2d6174dc1bb7d41e8ea5fd76724685000734f1d77b
504
+ e268927aa50d44de5365c11a2e402478767b7b98856a21a0715f9db65709aabb
505
+ ed5ecc6b0e2fdd81be806599d6509d166e26849049e60e8d8b398641282b1e5a
506
+ 72e0e61880cc5fc9c7b5990c2d40b22eba783391b72807d2d5349fb55875c015
507
+ ]
508
+ end
509
+ let(:merkle_tree4) do
510
+ %w[
511
+ 627c859b5af6d537930fd16148eb0597542bea543f65fc2b0e5f188b5a458529
512
+ d00b90525820a74f30ce26488db7f77c6ee9577e650568a051edd8560bbf83a1
513
+ 706b8ac1a433bc28385450626e12c1c7806032dc8b7e12221f417c5f22059d70
514
+ 10107ad569400a5f9621498e410845e6db0551671a2cafcf4358bd7867c6bc14
515
+ ac6b08a363aedd5e58177c7f68bb213403ef78d24be0012c06b3483a9e2461fe
516
+ d3074f5b33a44d9961f40eadf250cdc1425f7975012fccb6b06abc5202c53f4b
517
+ 3270c13599266d3a8da90a85a07fc003c58a8ff2938988356783b6261be335a6
518
+ e097c3e2e3a07385628ac5a5a775e8a5e22dda3732bee32ae65b1430d080fc32
519
+ c335a3963e8d89a9f46b94158d33f9b0dee25e776cba91be5eda44898bd31a78
520
+ eb52315c6b26f72fa58ed95cd4886f1aa047ecd8f34ed8a367f59854f20733d8
521
+ f97bf49e42e1732c0b515ecbac7cffc29c8c75c20c6783ad48b09d348fe0b6cf
522
+ fc655dfc41eed4e2ea4cfe33ebb6bf593eb256bf86c17802fd03567668d0bf71
523
+ 06c4abf5dae15d5fa3632e7e5f82f05e7afbbfd495ea8015c6094764d868654c
524
+ 31bbd6e4523aeaaaf75b6ea4ef63d0fe3dba66fb719f4a4232891a3b58ad5cec
525
+ 0c728622b795e14ac40c4aa13cb732a0407b2b85c9108c6f06c083220bb6d65d
526
+ f83f6ea46edcbeaa738ce4701bf48412a10c4b1a9f109efe44bc8fe5cb6b0017
527
+ 5e6168778c8407ace3ae9901a2f5197d6f21a6634ae0af639e52d14c39b13e02
528
+ b92a7980b8a8a64f896027c0de732298d04ca56bea66c18cf97983037486e456
529
+ 2a2fd5e450b6ec31ccbe9d827f2e903714eb69c351300b1e76c587aef60e000c
530
+ 9ed561bb49c47648e0250cb074721d94cba84ed1e083f1e57c29eca78e36d73d
531
+ ]
532
+ end
533
+
534
+ it 'produces the expected tree for a simple tree' do
535
+ expect(Bitcoin.hash_mrkl_tree(merkle_tree1[0...2])).to eq(merkle_tree1)
536
+ end
537
+
538
+ it 'produces the expected tree for a larger tree' do
539
+ expect(Bitcoin.hash_mrkl_tree(merkle_tree2[0...3])).to eq(merkle_tree2)
540
+
541
+ expect(
542
+ Bitcoin.bitcoin_mrkl(merkle_tree2[0], merkle_tree2[1])
543
+ ).to eq(merkle_tree2[3])
544
+ expect(
545
+ Bitcoin.bitcoin_mrkl(merkle_tree2[2], merkle_tree2[2])
546
+ ).to eq(merkle_tree2[4])
547
+ expect(
548
+ Bitcoin.bitcoin_mrkl(merkle_tree2[3], merkle_tree2[4])
549
+ ).to eq(merkle_tree2[5])
550
+
551
+ merkle_tree2[0...3].each.with_index do |target, idx|
552
+ branch = Bitcoin.hash_mrkl_branch(merkle_tree2[0...3], target)
553
+ expect(
554
+ Bitcoin.mrkl_branch_root(branch, target, idx)
555
+ ).to eq(merkle_tree2[-1])
556
+ end
557
+ end
558
+
559
+ it 'produces the expected results for a medium tree' do
560
+ expect(
561
+ Bitcoin.bitcoin_mrkl(merkle_tree3[0], merkle_tree3[1])
562
+ ).to eq(merkle_tree3[6])
563
+ expect(
564
+ Bitcoin.bitcoin_mrkl(merkle_tree3[2], merkle_tree3[3])
565
+ ).to eq(merkle_tree3[7])
566
+ expect(
567
+ Bitcoin.bitcoin_mrkl(merkle_tree3[4], merkle_tree3[5])
568
+ ).to eq(merkle_tree3[8])
569
+ expect(
570
+ Bitcoin.bitcoin_mrkl(merkle_tree3[6], merkle_tree3[7])
571
+ ).to eq(merkle_tree3[9])
572
+ expect(
573
+ Bitcoin.bitcoin_mrkl(merkle_tree3[8], merkle_tree3[8])
574
+ ).to eq(merkle_tree3[10])
575
+ expect(
576
+ Bitcoin.bitcoin_mrkl(merkle_tree3[9], merkle_tree3[10])
577
+ ).to eq(merkle_tree3[11])
578
+ expect(
579
+ Bitcoin.hash_mrkl_tree(merkle_tree3[0...6])
580
+ ).to eq(merkle_tree3)
581
+
582
+ merkle_tree3[0...5].each.with_index do |target, idx|
583
+ branch = Bitcoin.hash_mrkl_branch(merkle_tree3[0..5], target)
584
+ expect(
585
+ Bitcoin.mrkl_branch_root(branch, target, idx)
586
+ ).to eq(merkle_tree3[-1])
587
+ end
588
+ end
589
+
590
+ it 'produces the expected results for a very large tree' do
591
+ expect(
592
+ Bitcoin.bitcoin_mrkl(merkle_tree4[0], merkle_tree4[1])
593
+ ).to eq(merkle_tree4[9])
594
+ expect(
595
+ Bitcoin.bitcoin_mrkl(merkle_tree4[2], merkle_tree4[3])
596
+ ).to eq(merkle_tree4[10])
597
+ expect(
598
+ Bitcoin.bitcoin_mrkl(merkle_tree4[4], merkle_tree4[5])
599
+ ).to eq(merkle_tree4[11])
600
+ expect(
601
+ Bitcoin.bitcoin_mrkl(merkle_tree4[6], merkle_tree4[7])
602
+ ).to eq(merkle_tree4[12])
603
+ expect(
604
+ Bitcoin.bitcoin_mrkl(merkle_tree4[8], merkle_tree4[8])
605
+ ).to eq(merkle_tree4[13])
606
+
607
+ expect(
608
+ Bitcoin.bitcoin_mrkl(merkle_tree4[9], merkle_tree4[10])
609
+ ).to eq(merkle_tree4[14])
610
+ expect(
611
+ Bitcoin.bitcoin_mrkl(merkle_tree4[11], merkle_tree4[12])
612
+ ).to eq(merkle_tree4[15])
613
+ expect(
614
+ Bitcoin.bitcoin_mrkl(merkle_tree4[13], merkle_tree4[13])
615
+ ).to eq(merkle_tree4[16])
616
+ expect(
617
+ Bitcoin.bitcoin_mrkl(merkle_tree4[14], merkle_tree4[15])
618
+ ).to eq(merkle_tree4[17])
619
+ expect(
620
+ Bitcoin.bitcoin_mrkl(merkle_tree4[16], merkle_tree4[16])
621
+ ).to eq(merkle_tree4[18])
622
+ expect(
623
+ Bitcoin.bitcoin_mrkl(merkle_tree4[17], merkle_tree4[18])
624
+ ).to eq(merkle_tree4[19])
625
+
626
+ expect(Bitcoin.hash_mrkl_tree(merkle_tree4[0...9])).to eq(merkle_tree4)
627
+
628
+ merkle_tree4[0..8].each.with_index do |target, idx|
629
+ branch = Bitcoin.hash_mrkl_branch(merkle_tree4[0..8], target)
630
+ expect(
631
+ Bitcoin.mrkl_branch_root(branch, target, idx)
632
+ ).to eq(merkle_tree4[-1])
633
+ end
634
+ end
635
+
636
+ it 'does not allow duplicate hash in merkle trees' do
637
+ expect(
638
+ Bitcoin.hash_mrkl_tree(%w[aa bb cc]).last
639
+ ).not_to eq(Bitcoin.hash_mrkl_tree(%w[aa bb cc cc]).last)
640
+ end
641
+
642
+ it 'returns a value even if a merkle branch is empty' do
643
+ branch = []
644
+ mrkl_index = 0
645
+ target = '089b911f5e471c0e1800f3384281ebec5b372fbb6f358790a92747ade271ccdf'
646
+ expect(
647
+ Bitcoin.mrkl_branch_root(branch.map(&:hth), target, mrkl_index)
648
+ ).to eq(target)
649
+ end
650
+ end
651
+
652
+ describe '.decode_compact_bits / .encode_compact_bits' do
653
+ let(:target1) { 453_031_340 }
654
+ let(:target2) { 486_604_799 }
655
+ let(:target3) { 476_399_191 } # from block 40,320
656
+
657
+ it 'decodes nonce compact bits to bignum hex' do
658
+ expect(
659
+ Bitcoin.decode_compact_bits(target1).index(/[^0]/)
660
+ ).to eq(12)
661
+
662
+ expect(
663
+ Bitcoin.decode_compact_bits(target1).to_i(16)
664
+ ).to eq(
665
+ '000000000000b5ac000000000000000000000000000000000000000000000000'.to_i(16)
666
+ )
667
+ expect(
668
+ Bitcoin.decode_compact_bits(target1)
669
+ ).to eq('000000000000b5ac000000000000000000000000000000000000000000000000')
670
+ expect(
671
+ Bitcoin.decode_compact_bits(target2)
672
+ ).to eq('00000000ffff0000000000000000000000000000000000000000000000000000')
673
+ expect(
674
+ Bitcoin.decode_compact_bits(target3)
675
+ ).to eq('0000000065465700000000000000000000000000000000000000000000000000')
676
+
677
+ # TODO: Remove this commented out test if it cannot be made to work.
678
+ # Bitcoin.network = :dogecoin
679
+ # expect(Bitcoin.decode_compact_bits('01fedcba'.to_i(16)).to_i(16)).to eq(-0x7e)
680
+ end
681
+
682
+ it 'encodes to the expected values' do
683
+ expect(
684
+ Bitcoin.encode_compact_bits(Bitcoin.decode_compact_bits(target1))
685
+ ).to eq(target1)
686
+ expect(
687
+ Bitcoin.encode_compact_bits(Bitcoin.decode_compact_bits(target2))
688
+ ).to eq(target2)
689
+ expect(
690
+ Bitcoin.encode_compact_bits(Bitcoin.decode_compact_bits(target3))
691
+ ).to eq(target3)
692
+ end
693
+ end
694
+
695
+ describe '.block_hash' do
696
+ # Block #0, n_tx: 1
697
+ let(:prev_block0) { '0000000000000000000000000000000000000000000000000000000000000000' }
698
+ let(:merkle_root0) { '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b' }
699
+ let(:time_bits_nonce_ver0) { [1_231_006_505, 486_604_799, 2_083_236_893, 1] }
700
+ let(:expected_block_hash0) do
701
+ '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
702
+ end
703
+
704
+ # Block #1, n_tx: 1
705
+ let(:prev_block1) { '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' }
706
+ let(:merkle_root1) { '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098' }
707
+ let(:time_bits_nonce_ver1) { [1_231_469_665, 486_604_799, 2_573_394_689, 1] }
708
+ let(:expected_block_hash1) do
709
+ '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048'
710
+ end
711
+
712
+ # Block #169, n_tx: 1
713
+ let(:prev_block169) { '00000000567e95797f93675ac23683ae3787b183bb36859c18d9220f3fa66a69' }
714
+ let(:merkle_root169) { 'd7b9a9da6becbf47494c27e913241e5a2b85c5cceba4b2f0d8305e0a87b92d98' }
715
+ let(:time_bits_nonce_ver169) { [1_231_730_523, 486_604_799, 3_718_213_931, 1] }
716
+ let(:expected_block_hash169) do
717
+ '000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55'
718
+ end
719
+
720
+ # Block #171, n_tx: 1
721
+ let(:prev_block171) { '00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee' }
722
+ let(:merkle_root171) { 'd5f2d21453a6f0e67b5c42959c9700853e4c4d46fa7519d1cc58e77369c893f2' }
723
+ let(:time_bits_nonce_ver171) { [1_231_731_401, 486_604_799, 653_436_935, 1] }
724
+ let(:expected_block_hash171) do
725
+ '00000000c9ec538cab7f38ef9c67a95742f56ab07b0a37c5be6b02808dbfb4e0'
726
+ end
727
+
728
+ it 'produces the expected block hash' do
729
+ expect(
730
+ Bitcoin.block_hash(prev_block0, merkle_root0, *time_bits_nonce_ver0)
731
+ ).to eq(expected_block_hash0)
732
+ expect(
733
+ Bitcoin.block_hash(prev_block1, merkle_root1, *time_bits_nonce_ver1)
734
+ ).to eq(expected_block_hash1)
735
+ expect(
736
+ Bitcoin.block_hash(prev_block169, merkle_root169, *time_bits_nonce_ver169)
737
+ ).to eq(expected_block_hash169)
738
+ expect(
739
+ Bitcoin.block_hash(prev_block171, merkle_root171, *time_bits_nonce_ver171)
740
+ ).to eq(expected_block_hash171)
741
+ end
742
+ end
743
+
744
+ describe '.generate_key' do
745
+ it 'generates an openssl-secp256k1 private/public keypair' do
746
+ private_key, public_key = Bitcoin.generate_key
747
+
748
+ expect(private_key.size).to eq(64) # bytes in hex
749
+ expect(public_key.size).to eq(130) # bytes in hex
750
+
751
+ key = Bitcoin.open_key(private_key, public_key)
752
+ expect(Bitcoin.inspect_key(key)).to eq([private_key, public_key])
753
+ end
754
+ end
755
+
756
+ describe 'Bitcoin::OpenSSL_EC' do
757
+ it 'OpenSSL library is available' do
758
+ expect do
759
+ Bitcoin::OpenSSL_EC
760
+ end.not_to raise_error
761
+ end
762
+
763
+ describe 'Bitcoin.open_key' do
764
+ it 'opens key from private key and resolves public key' do
765
+ 50.times do
766
+ private_key, public_key = Bitcoin.generate_key
767
+ key = Bitcoin.open_key(private_key)
768
+
769
+ expect(key.private_key_hex).to eq(private_key)
770
+ expect(key.public_key_hex).to eq(public_key)
771
+ end
772
+ end
773
+ end
774
+
775
+ describe '.der_to_private_key' do
776
+ it 'extracts the private key from uncompressed DER format' do
777
+ der =
778
+ '308201130201010420a29fe0f28b2936dbc89f889f74cd1f0662d18a873ac15d6c' \
779
+ 'd417b808db1ccd0aa081a53081a2020101302c06072a8648ce3d0101022100ffff' \
780
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604' \
781
+ '010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959' \
782
+ 'f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47' \
783
+ 'd08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03b' \
784
+ 'bfd25e8cd0364141020101a14403420004768cfc6c44b927b0e69e9dd343e96132' \
785
+ 'f7cd1d360d8cb8d65c83d89d7beaceadfd19918e076606a099344156acdb026b10' \
786
+ '65a958e39f098cfd0a34dd976291d6'
787
+
788
+ expect(
789
+ Bitcoin::OpenSSL_EC.der_to_private_key(der)
790
+ ).to eq('a29fe0f28b2936dbc89f889f74cd1f0662d18a873ac15d6cd417b808db1ccd0a')
791
+ end
792
+
793
+ describe 'signing and verifying messages' do
794
+ context 'testnet' do
795
+ before { Bitcoin.network = :testnet3 }
796
+
797
+ it 'verifies the signature of a testnet address' do
798
+ expect(
799
+ Bitcoin.verify_message(
800
+ 'mwPVMbZQgkpwJJt2YP3sLSgbEBQw3FWZSc',
801
+ 'H5GER0Nz+L7TPZMQzXtv0hnLSsyfPok9lkdHIv01vksREpEpOhTPTonU1xvy' \
802
+ 'PAOIIKhU3++Ol+LaWKWmsfyxDXk=',
803
+ 'A' * 500
804
+ )
805
+ ).to be true
806
+ end
807
+ end
808
+
809
+ context 'mainnet' do
810
+ before { Bitcoin.network = :bitcoin }
811
+ let(:address_and_keys1) do
812
+ %w[
813
+ 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ
814
+ 12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747
815
+ 040b4c866585dd868a9d62348a9cd008d6a312937048fff31670e7e920cfc7a7 \
816
+ 447b5f0bba9e01e6fe4735c8383e6e7a3347a0fd72381b8f797a19f694054e5a69
817
+ ]
818
+ end
819
+ let(:address_and_keys2) do
820
+ %w[
821
+ 1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs
822
+ 12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747
823
+ 030b4c866585dd868a9d62348a9cd008d6a312937048fff31670e7e920cfc7a744
824
+ ]
825
+ end
826
+
827
+ it 'successfully signs and verifies the message' do
828
+ [address_and_keys1, address_and_keys2].each do |_addr, privkey, _pubkey|
829
+ key = Bitcoin.open_key(privkey)
830
+ 16.times.each do |count|
831
+ signature = Bitcoin.sign_message(
832
+ key.private_key_hex,
833
+ key.public_key_hex,
834
+ format('Very secret message %<count>d: 11', count: count)
835
+ )
836
+ expect(
837
+ Bitcoin.verify_message(
838
+ signature['address'],
839
+ 'invalid-signature',
840
+ signature['message']
841
+ )
842
+ ).to be false
843
+ expect(
844
+ Bitcoin.verify_message(
845
+ signature['address'],
846
+ signature['signature'],
847
+ signature['message']
848
+ )
849
+ ).to be true
850
+ end
851
+ end
852
+ end
853
+ end
854
+ end
855
+ end
856
+ end
857
+
858
+ describe '.generate_address' do
859
+ it 'generates a new bitcoin address' do
860
+ address, private_key, public_key, _hash160 = Bitcoin.generate_address
861
+
862
+ expect(private_key.size).to eq(64) # bytes in hex
863
+ expect(public_key.size).to eq(130) # bytes in hex
864
+ expect(
865
+ Bitcoin.hash160_to_address(Bitcoin.hash160(public_key))
866
+ ).to eq(address)
867
+ end
868
+ end
869
+
870
+ describe '.encode_base58 / decode_base58' do
871
+ it 'passes tests from bitcoin core' do
872
+ # fixtures from: https://github.com/bitcoin/bitcoin/blob/master/src/test/base58_tests.cpp
873
+ bin = [
874
+ '',
875
+ "\x61",
876
+ "\x62\x62\x62",
877
+ "\x63\x63\x63",
878
+ "\x73\x69\x6d\x70\x6c\x79\x20\x61\x20\x6c\x6f\x6e\x67\x20\x73\x74\x72\x69\x6e\x67",
879
+ "\x00\xeb\x15\x23\x1d\xfc\xeb\x60\x92\x58\x86\xb6\x7d\x06\x52\x99\x92" \
880
+ "\x59\x15\xae\xb1\x72\xc0\x66\x47",
881
+ "\x51\x6b\x6f\xcd\x0f",
882
+ "\xbf\x4f\x89\x00\x1e\x67\x02\x74\xdd",
883
+ "\x57\x2e\x47\x94",
884
+ "\xec\xac\x89\xca\xd9\x39\x23\xc0\x23\x21",
885
+ "\x10\xc8\x51\x1e",
886
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
887
+ ]
888
+ out = [
889
+ '',
890
+ '2g',
891
+ 'a3gV',
892
+ 'aPEr',
893
+ '2cFupjhnEsSn59qHXstmK2ffpLv2',
894
+ '1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L',
895
+ 'ABnLTmg',
896
+ '3SEo3LWLoPntC',
897
+ '3EFU7m',
898
+ 'EJDM8drfXA6uyA',
899
+ 'Rt5zm',
900
+ '1111111111'
901
+ ]
902
+
903
+ fixtures = bin.zip(out).map { |b, o| [b.unpack('H*')[0], o] }
904
+ fixtures.each do |hex, output|
905
+ expect(Bitcoin.encode_base58(hex)).to eq(output)
906
+ expect(Bitcoin.decode_base58(output)).to eq(hex)
907
+ end
908
+ end
909
+ end
910
+
911
+ it '.block_next_retarget' do
912
+ expect(Bitcoin.block_next_retarget(189_408)).to eq(189_503)
913
+ expect(Bitcoin.block_next_retarget(189_503)).to eq(189_503)
914
+ expect(Bitcoin.block_next_retarget(189_504)).to eq(191_519)
915
+ end
916
+
917
+ it '.block_difficulty' do
918
+ expect(Bitcoin.block_difficulty(436_835_377)).to eq('1751454.5353407')
919
+ end
920
+
921
+ describe '.block_new_target' do
922
+ before { Bitcoin.network = :bitcoin }
923
+
924
+ it 'should calculate retarget difficulty' do
925
+ prev_height = 201_599
926
+ prev_block_time = 1_349_227_021
927
+ prev_block_bits = 0x1a05db8b
928
+ last_retarget_time = 1_348_092_851
929
+ new_difficulty = Bitcoin.block_new_target(
930
+ prev_height, prev_block_time, prev_block_bits, last_retarget_time
931
+ )
932
+
933
+ expect(
934
+ Bitcoin.decode_compact_bits(new_difficulty)
935
+ ).to eq(Bitcoin.decode_compact_bits(0x1a057e08))
936
+ end
937
+ end
938
+
939
+ it '.block_hashes_to_win' do
940
+ expect(Bitcoin.block_hashes_to_win(436_835_377))
941
+ .to eq(7_522_554_734_795_001)
942
+ end
943
+
944
+ it '.block_probability' do
945
+ expect(Bitcoin.block_probability(436_835_377))
946
+ .to eq('0.0000000000000001329335625003267087884673003372881794348')
947
+ end
948
+
949
+ it '.block_average_hashing_time' do
950
+ expect(
951
+ Bitcoin.block_average_hashing_time(436_835_377, 630_000_000)
952
+ ).to eq(11_940_563)
953
+ end
954
+
955
+ it '.block_average_mining_time' do
956
+ expect(
957
+ Bitcoin.block_average_mining_time(0x1a022fbe, 231_337, 270.0, 1.0)
958
+ ).to eq(56.50855038530773) # days
959
+ end
960
+
961
+ it '.blockchain_total_btc' do
962
+ block_heights = [0, 209_999, 210_000, 419_999, 420_000, 1_680_000]
963
+ expected_results = [
964
+ [5_000_000_000, 1, 5_000_000_000, 0],
965
+ [1_050_000_000_000_000, 1, 5_000_000_000, 209_999],
966
+ [1_050_005_000_000_000, 2, 2_500_000_000, 210_000],
967
+ [1_575_002_500_000_000, 2, 2_500_000_000, 419_999],
968
+ [1_575_005_000_000_000, 3, 1_250_000_000, 4_200_00],
969
+ [2_091_801_875_000_000, 9, 19_531_250, 1_680_000]
970
+ ]
971
+
972
+ block_heights.zip(expected_results).map do |height, expected_result|
973
+ expect(Bitcoin.blockchain_total_btc(height)).to eq(expected_result)
974
+ end
975
+ end
976
+
977
+ it '.block_creation_reward' do
978
+ heights = [0, 209_999, 210_000, 419_999, 420_000, 1_680_000]
979
+ rewards = [
980
+ 5_000_000_000,
981
+ 5_000_000_000,
982
+ 2_500_000_000,
983
+ 2_500_000_000,
984
+ 1_250_000_000,
985
+ 19_531_250
986
+ ]
987
+
988
+ heights.zip(rewards).map do |height, reward|
989
+ expect(Bitcoin.block_creation_reward(height)).to eq(reward)
990
+ end
991
+ end
992
+
993
+ describe 'bitcoin base58 test vectors' do
994
+ # Port of Bitcoin Core test vectors.
995
+ # https://github.com/bitcoin/bitcoin/blob/595a7bab23bc21049526229054ea1fff1a29c0bf/src/test/base58_tests.cpp#L139
996
+ let(:valid_base58_keys) do
997
+ JSON.parse(fixtures_file('base58_keys_valid.json'))
998
+ end
999
+ # Port of Bitcoin Core test vectors.
1000
+ # https://github.com/bitcoin/bitcoin/blob/595a7bab23bc21049526229054ea1fff1a29c0bf/src/test/base58_tests.cpp#L179
1001
+ let(:invalid_base58_keys) do
1002
+ JSON.parse(fixtures_file('base58_keys_invalid.json'))
1003
+ end
1004
+
1005
+ it 'passes the valid keys cases' do
1006
+ valid_base58_keys.each do |test_case|
1007
+ # NOTE: Single element arrays in tests are comments
1008
+ next if test_case.length == 1
1009
+
1010
+ address = test_case[0]
1011
+ script = test_case[1].htb
1012
+ is_privkey = test_case[2].fetch('isPrivkey')
1013
+ is_swapcase_valid = test_case[2].fetch('tryCaseFlip', false)
1014
+
1015
+ Bitcoin.network =
1016
+ case test_case[2].fetch('chain').to_sym
1017
+ when :main then :bitcoin
1018
+ when :test then :testnet3
1019
+ when :regtest then :regtest
1020
+ end
1021
+
1022
+ # This spec only tests address generation, not base58 private key encoding
1023
+ next if is_privkey
1024
+
1025
+ computed_script = Bitcoin::Script.to_address_script(address)
1026
+ expect(computed_script).to eq(script)
1027
+
1028
+ expect(Bitcoin.valid_address?(address.swapcase)).to eq(is_swapcase_valid)
1029
+
1030
+ computed_address = Bitcoin::Script.new(script).get_address
1031
+ expect(computed_address).to eq(address)
1032
+ end
1033
+ end
1034
+
1035
+ it 'fails the invalid keys cases' do
1036
+ test_cases = JSON.parse(fixtures_file('base58_keys_invalid.json'))
1037
+ test_cases.each do |test_case|
1038
+ address = test_case[0]
1039
+
1040
+ %i[bitcoin testnet3 regtest].each do |network_name|
1041
+ Bitcoin.network = network_name
1042
+ expect(Bitcoin.valid_address?(address)).to be false
1043
+ end
1044
+ end
1045
+ end
1046
+ end
1047
+
1048
+ describe 'Bitcoin-Wiki - Common Standards - Hashes' do
1049
+ # https://en.bitcoin.it/wiki/Protocol_specification
1050
+ # Hashes
1051
+ # Usually, when a hash is computed within bitcoin, it is computed twice.
1052
+ # Most of the time SHA-256 hashes are used, however RIPEMD-160 is also
1053
+ # used when a shorter hash is desirable.
1054
+ require 'digest/sha2'
1055
+ require 'digest/rmd160'
1056
+
1057
+ it 'double-SHA-256 encoding of string "hello"' do
1058
+ # first round sha256
1059
+ expect(Digest::SHA256.hexdigest('hello'))
1060
+ .to eq('2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824')
1061
+
1062
+ # second round sha256
1063
+ expect(
1064
+ Digest::SHA256.hexdigest(Digest::SHA256.digest('hello'))
1065
+ ).to eq('9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50')
1066
+ end
1067
+
1068
+ it 'RIPEMD-160 encoding of string "hello"' do
1069
+ # first round sha256
1070
+ expect(Digest::SHA256.hexdigest('hello'))
1071
+ .to eq('2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824')
1072
+
1073
+ # second round rmd160
1074
+ expect(
1075
+ Digest::RMD160.hexdigest(Digest::SHA256.digest('hello'))
1076
+ ).to eq('b6a9c8c230722b7c748331a8b450f05566dc7d0f')
1077
+ end
1078
+ end
1079
+ end