bitcoin-ruby 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +46 -0
  5. data/.travis.yml +5 -1
  6. data/Gemfile +11 -9
  7. data/Gemfile.lock +64 -12
  8. data/README.rdoc +17 -4
  9. data/Rakefile +58 -83
  10. data/bitcoin-ruby.gemspec +5 -2
  11. data/lib/bitcoin.rb +31 -14
  12. data/lib/bitcoin/bech32.rb +126 -132
  13. data/lib/bitcoin/bloom_filter.rb +24 -21
  14. data/lib/bitcoin/builder.rb +168 -126
  15. data/lib/bitcoin/connection.rb +21 -24
  16. data/lib/bitcoin/contracthash.rb +20 -24
  17. data/lib/bitcoin/dogecoin.rb +79 -77
  18. data/lib/bitcoin/electrum/mnemonic.rb +28 -25
  19. data/lib/bitcoin/ext_key.rb +3 -3
  20. data/lib/bitcoin/ffi/bitcoinconsensus.rb +17 -13
  21. data/lib/bitcoin/ffi/openssl.rb +355 -338
  22. data/lib/bitcoin/ffi/secp256k1.rb +97 -64
  23. data/lib/bitcoin/protocol.rb +6 -3
  24. data/lib/bitcoin/protocol/address.rb +15 -13
  25. data/lib/bitcoin/protocol/aux_pow.rb +12 -15
  26. data/lib/bitcoin/protocol/block.rb +102 -76
  27. data/lib/bitcoin/protocol/handler.rb +2 -4
  28. data/lib/bitcoin/protocol/parser.rb +108 -92
  29. data/lib/bitcoin/protocol/partial_merkle_tree.rb +59 -47
  30. data/lib/bitcoin/protocol/reject.rb +26 -28
  31. data/lib/bitcoin/protocol/script_witness.rb +3 -8
  32. data/lib/bitcoin/protocol/tx.rb +250 -137
  33. data/lib/bitcoin/protocol/txin.rb +44 -38
  34. data/lib/bitcoin/protocol/txout.rb +27 -20
  35. data/lib/bitcoin/protocol/version.rb +47 -34
  36. data/lib/bitcoin/script.rb +18 -17
  37. data/lib/bitcoin/trezor/mnemonic.rb +113 -98
  38. data/lib/bitcoin/version.rb +1 -1
  39. data/spec/examples.txt +399 -0
  40. data/spec/{bitcoin/fixtures → fixtures}/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +0 -0
  41. data/spec/{bitcoin/fixtures → fixtures}/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +0 -0
  42. data/spec/{bitcoin/fixtures → fixtures}/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +0 -0
  43. data/spec/{bitcoin/fixtures → fixtures}/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +0 -0
  44. data/spec/{bitcoin/fixtures → fixtures}/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +0 -0
  45. data/spec/{bitcoin/fixtures → fixtures}/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +0 -0
  46. data/spec/{bitcoin/fixtures → fixtures}/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +0 -0
  47. data/spec/{bitcoin/fixtures → fixtures}/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +0 -0
  48. data/spec/{bitcoin/fixtures → fixtures}/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +0 -0
  49. data/spec/{bitcoin/fixtures → fixtures}/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +0 -0
  50. data/spec/{bitcoin/fixtures → fixtures}/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +0 -0
  51. data/spec/{bitcoin/fixtures → fixtures}/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +0 -0
  52. data/spec/{bitcoin/fixtures → fixtures}/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +0 -0
  53. data/spec/{bitcoin/fixtures → fixtures}/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +0 -0
  54. data/spec/{bitcoin/fixtures → fixtures}/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +0 -0
  55. data/spec/{bitcoin/fixtures → fixtures}/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +0 -0
  56. data/spec/{bitcoin/fixtures → fixtures}/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +0 -0
  57. data/spec/{bitcoin/fixtures → fixtures}/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +0 -0
  58. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_invalid.json +0 -0
  59. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_valid.json +0 -0
  60. data/spec/{bitcoin/fixtures → fixtures}/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +0 -0
  61. data/spec/{bitcoin/fixtures → fixtures}/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +0 -0
  62. data/spec/{bitcoin/fixtures → fixtures}/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  63. data/spec/{bitcoin/fixtures → fixtures}/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +0 -0
  64. data/spec/{bitcoin/fixtures → fixtures}/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +0 -0
  65. data/spec/{bitcoin/fixtures → fixtures}/coinbase-toshi.json +0 -0
  66. data/spec/{bitcoin/fixtures → fixtures}/coinbase.json +0 -0
  67. data/spec/{bitcoin/fixtures → fixtures}/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  68. data/spec/{bitcoin/fixtures → fixtures}/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +0 -0
  69. data/spec/{bitcoin/fixtures → fixtures}/filteredblock-0.bin +0 -0
  70. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  71. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +0 -0
  72. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  73. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +0 -0
  74. data/spec/{bitcoin/fixtures → fixtures}/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +0 -0
  75. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.bin +0 -0
  76. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.json +0 -0
  77. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.bin +0 -0
  78. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.json +0 -0
  79. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.bin +0 -0
  80. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.json +0 -0
  81. data/spec/{bitcoin/fixtures → fixtures}/rawblock-170.bin +0 -0
  82. data/spec/{bitcoin/fixtures → fixtures}/rawblock-9.bin +0 -0
  83. data/spec/{bitcoin/fixtures → fixtures}/rawblock-auxpow.bin +0 -0
  84. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-1151351.bin +0 -0
  85. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.bin +0 -0
  86. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.json +0 -0
  87. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-265322.bin +0 -0
  88. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01-toshi.json +0 -0
  89. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.bin +0 -0
  90. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.json +0 -0
  91. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02-toshi.json +0 -0
  92. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.bin +0 -0
  93. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.json +0 -0
  94. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03-toshi.json +0 -0
  95. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.bin +0 -0
  96. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.json +0 -0
  97. data/spec/{bitcoin/fixtures → fixtures}/rawtx-04.json +0 -0
  98. data/spec/{bitcoin/fixtures → fixtures}/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
  99. data/spec/{bitcoin/fixtures → fixtures}/rawtx-05.json +0 -0
  100. data/spec/{bitcoin/fixtures → fixtures}/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
  101. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
  102. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +0 -0
  103. data/spec/{bitcoin/fixtures → fixtures}/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +0 -0
  104. data/spec/{bitcoin/fixtures → fixtures}/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
  105. data/spec/{bitcoin/fixtures → fixtures}/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
  106. data/spec/{bitcoin/fixtures → fixtures}/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +0 -0
  107. data/spec/{bitcoin/fixtures → fixtures}/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +0 -0
  108. data/spec/{bitcoin/fixtures → fixtures}/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +0 -0
  109. data/spec/{bitcoin/fixtures → fixtures}/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
  110. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.bin +0 -0
  111. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.json +0 -0
  112. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  113. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  114. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  115. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  116. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +0 -0
  117. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  118. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
  119. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +0 -0
  120. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  121. data/spec/{bitcoin/fixtures → fixtures}/script_tests.json +0 -0
  122. data/spec/{bitcoin/fixtures → fixtures}/sighash.json +0 -0
  123. data/spec/{bitcoin/fixtures → fixtures}/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +0 -0
  124. data/spec/{bitcoin/fixtures → fixtures}/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +0 -0
  125. data/spec/{bitcoin/fixtures → fixtures}/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +0 -0
  126. data/spec/{bitcoin/fixtures → fixtures}/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +0 -0
  127. data/spec/{bitcoin/fixtures → fixtures}/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +0 -0
  128. data/spec/{bitcoin/fixtures → fixtures}/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +0 -0
  129. data/spec/{bitcoin/fixtures → fixtures}/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +0 -0
  130. data/spec/{bitcoin/fixtures → fixtures}/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +0 -0
  131. data/spec/{bitcoin/fixtures → fixtures}/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +0 -0
  132. data/spec/{bitcoin/fixtures → fixtures}/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +0 -0
  133. data/spec/{bitcoin/fixtures → fixtures}/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +0 -0
  134. data/spec/{bitcoin/fixtures → fixtures}/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +0 -0
  135. data/spec/{bitcoin/fixtures → fixtures}/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +0 -0
  136. data/spec/{bitcoin/fixtures → fixtures}/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +0 -0
  137. data/spec/{bitcoin/fixtures → fixtures}/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +0 -0
  138. data/spec/{bitcoin/fixtures → fixtures}/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +0 -0
  139. data/spec/{bitcoin/fixtures → fixtures}/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +0 -0
  140. data/spec/{bitcoin/fixtures → fixtures}/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +0 -0
  141. data/spec/{bitcoin/fixtures → fixtures}/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +0 -0
  142. data/spec/{bitcoin/fixtures → fixtures}/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +0 -0
  143. data/spec/{bitcoin/fixtures → fixtures}/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +0 -0
  144. data/spec/{bitcoin/fixtures → fixtures}/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +0 -0
  145. data/spec/{bitcoin/fixtures → fixtures}/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +0 -0
  146. data/spec/{bitcoin/fixtures → fixtures}/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +0 -0
  147. data/spec/{bitcoin/fixtures → fixtures}/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +0 -0
  148. data/spec/{bitcoin/fixtures → fixtures}/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +0 -0
  149. data/spec/{bitcoin/fixtures → fixtures}/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +0 -0
  150. data/spec/{bitcoin/fixtures → fixtures}/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +0 -0
  151. data/spec/{bitcoin/fixtures → fixtures}/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +0 -0
  152. data/spec/{bitcoin/fixtures → fixtures}/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +0 -0
  153. data/spec/{bitcoin/fixtures → fixtures}/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +0 -0
  154. data/spec/{bitcoin/fixtures → fixtures}/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +0 -0
  155. data/spec/{bitcoin/fixtures → fixtures}/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +0 -0
  156. data/spec/{bitcoin/fixtures → fixtures}/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +0 -0
  157. data/spec/{bitcoin/fixtures → fixtures}/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +0 -0
  158. data/spec/{bitcoin/fixtures → fixtures}/tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json +0 -0
  159. data/spec/{bitcoin/fixtures → fixtures}/tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json +0 -0
  160. data/spec/{bitcoin/fixtures → fixtures}/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +0 -0
  161. data/spec/{bitcoin/fixtures → fixtures}/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +0 -0
  162. data/spec/{bitcoin/fixtures → fixtures}/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +0 -0
  163. data/spec/{bitcoin/fixtures → fixtures}/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +0 -0
  164. data/spec/{bitcoin/fixtures → fixtures}/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +0 -0
  165. data/spec/{bitcoin/fixtures → fixtures}/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +0 -0
  166. data/spec/{bitcoin/fixtures → fixtures}/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +0 -0
  167. data/spec/{bitcoin/fixtures → fixtures}/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +0 -0
  168. data/spec/{bitcoin/fixtures → fixtures}/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +0 -0
  169. data/spec/{bitcoin/fixtures → fixtures}/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +0 -0
  170. data/spec/{bitcoin/fixtures → fixtures}/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +0 -0
  171. data/spec/{bitcoin/fixtures → fixtures}/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +0 -0
  172. data/spec/{bitcoin/fixtures → fixtures}/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +0 -0
  173. data/spec/{bitcoin/fixtures → fixtures}/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +0 -0
  174. data/spec/helpers/block_helpers.rb +58 -0
  175. data/spec/helpers/fixture_helpers.rb +20 -0
  176. data/spec/helpers/library_helpers.rb +15 -0
  177. data/spec/spec_helper.rb +109 -0
  178. data/spec/unit/bitcoin/bech32_spec.rb +187 -0
  179. data/spec/unit/bitcoin/bitcoin_spec.rb +1079 -0
  180. data/spec/unit/bitcoin/bloom_filter_spec.rb +33 -0
  181. data/spec/unit/bitcoin/builder_spec.rb +559 -0
  182. data/spec/unit/bitcoin/contracthash_spec.rb +52 -0
  183. data/spec/unit/bitcoin/ext_key_spec.rb +281 -0
  184. data/spec/unit/bitcoin/key_spec.rb +457 -0
  185. data/spec/unit/bitcoin/network_spec.rb +71 -0
  186. data/spec/unit/bitcoin/protocol/addr_spec.rb +90 -0
  187. data/spec/unit/bitcoin/protocol/aux_pow_spec.rb +45 -0
  188. data/spec/unit/bitcoin/protocol/bip143_spec.rb +334 -0
  189. data/spec/unit/bitcoin/protocol/block_spec.rb +280 -0
  190. data/spec/unit/bitcoin/protocol/getblocks_spec.rb +44 -0
  191. data/spec/unit/bitcoin/protocol/inv_spec.rb +166 -0
  192. data/spec/unit/bitcoin/protocol/notfound_spec.rb +44 -0
  193. data/spec/unit/bitcoin/protocol/parser_spec.rb +69 -0
  194. data/spec/unit/bitcoin/protocol/partial_merkle_tree_spec.rb +47 -0
  195. data/spec/unit/bitcoin/protocol/ping_spec.rb +62 -0
  196. data/spec/unit/bitcoin/protocol/tx_spec.rb +1515 -0
  197. data/spec/unit/bitcoin/protocol/txin_spec.rb +47 -0
  198. data/spec/unit/bitcoin/protocol/txout_spec.rb +36 -0
  199. data/spec/unit/bitcoin/protocol/version_spec.rb +121 -0
  200. data/spec/unit/bitcoin/script/opcodes_spec.rb +864 -0
  201. data/spec/unit/bitcoin/script/script_spec.rb +1610 -0
  202. data/spec/unit/bitcoin/secp256k1_spec.rb +138 -0
  203. data/spec/unit/bitcoin/trezor/mnemonic_spec.rb +193 -0
  204. data/spec/unit/integrations/dogecoin_spec.rb +215 -0
  205. metadata +381 -372
  206. data/lib/bitcoin/logger.rb +0 -86
  207. data/lib/bitcoin/protocol/alert.rb +0 -46
  208. data/spec/bitcoin/bech32_spec.rb +0 -160
  209. data/spec/bitcoin/bitcoin_spec.rb +0 -666
  210. data/spec/bitcoin/bloom_filter_spec.rb +0 -23
  211. data/spec/bitcoin/builder_spec.rb +0 -375
  212. data/spec/bitcoin/contracthash_spec.rb +0 -45
  213. data/spec/bitcoin/dogecoin_spec.rb +0 -176
  214. data/spec/bitcoin/ext_key_spec.rb +0 -180
  215. data/spec/bitcoin/ffi_openssl.rb +0 -45
  216. data/spec/bitcoin/fixtures/rawblock-170.json +0 -68
  217. data/spec/bitcoin/fixtures/rawblock-9.json +0 -39
  218. data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
  219. data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
  220. data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
  221. data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
  222. data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
  223. data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
  224. data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
  225. data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
  226. data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
  227. data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
  228. data/spec/bitcoin/fixtures/txdp-1.txt +0 -32
  229. data/spec/bitcoin/fixtures/txdp-2-signed.txt +0 -19
  230. data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +0 -14
  231. data/spec/bitcoin/helpers/fake_blockchain.rb +0 -183
  232. data/spec/bitcoin/key_spec.rb +0 -326
  233. data/spec/bitcoin/network_spec.rb +0 -50
  234. data/spec/bitcoin/performance/storage_spec.rb +0 -41
  235. data/spec/bitcoin/protocol/addr_spec.rb +0 -82
  236. data/spec/bitcoin/protocol/alert_spec.rb +0 -22
  237. data/spec/bitcoin/protocol/aux_pow_spec.rb +0 -45
  238. data/spec/bitcoin/protocol/bip143_spec.rb +0 -116
  239. data/spec/bitcoin/protocol/block_spec.rb +0 -208
  240. data/spec/bitcoin/protocol/getblocks_spec.rb +0 -32
  241. data/spec/bitcoin/protocol/inv_spec.rb +0 -134
  242. data/spec/bitcoin/protocol/notfound_spec.rb +0 -31
  243. data/spec/bitcoin/protocol/parser_spec.rb +0 -50
  244. data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +0 -38
  245. data/spec/bitcoin/protocol/ping_spec.rb +0 -51
  246. data/spec/bitcoin/protocol/reject.rb +0 -17
  247. data/spec/bitcoin/protocol/tx_spec.rb +0 -894
  248. data/spec/bitcoin/protocol/txin_spec.rb +0 -45
  249. data/spec/bitcoin/protocol/txout_spec.rb +0 -33
  250. data/spec/bitcoin/protocol/version_spec.rb +0 -110
  251. data/spec/bitcoin/script/opcodes_spec.rb +0 -773
  252. data/spec/bitcoin/script/script_spec.rb +0 -977
  253. data/spec/bitcoin/secp256k1_spec.rb +0 -78
  254. data/spec/bitcoin/spec_helper.rb +0 -108
  255. data/spec/bitcoin/trezor/mnemonic_spec.rb +0 -161
@@ -0,0 +1,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