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.
- checksums.yaml +5 -5
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.rubocop.yml +46 -0
- data/.travis.yml +5 -1
- data/Gemfile +11 -9
- data/Gemfile.lock +64 -12
- data/README.rdoc +17 -4
- data/Rakefile +58 -83
- data/bitcoin-ruby.gemspec +5 -2
- data/lib/bitcoin.rb +31 -14
- data/lib/bitcoin/bech32.rb +126 -132
- data/lib/bitcoin/bloom_filter.rb +24 -21
- data/lib/bitcoin/builder.rb +168 -126
- data/lib/bitcoin/connection.rb +21 -24
- data/lib/bitcoin/contracthash.rb +20 -24
- data/lib/bitcoin/dogecoin.rb +79 -77
- data/lib/bitcoin/electrum/mnemonic.rb +28 -25
- data/lib/bitcoin/ext_key.rb +3 -3
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +17 -13
- data/lib/bitcoin/ffi/openssl.rb +355 -338
- data/lib/bitcoin/ffi/secp256k1.rb +97 -64
- data/lib/bitcoin/protocol.rb +6 -3
- data/lib/bitcoin/protocol/address.rb +15 -13
- data/lib/bitcoin/protocol/aux_pow.rb +12 -15
- data/lib/bitcoin/protocol/block.rb +102 -76
- data/lib/bitcoin/protocol/handler.rb +2 -4
- data/lib/bitcoin/protocol/parser.rb +108 -92
- data/lib/bitcoin/protocol/partial_merkle_tree.rb +59 -47
- data/lib/bitcoin/protocol/reject.rb +26 -28
- data/lib/bitcoin/protocol/script_witness.rb +3 -8
- data/lib/bitcoin/protocol/tx.rb +250 -137
- data/lib/bitcoin/protocol/txin.rb +44 -38
- data/lib/bitcoin/protocol/txout.rb +27 -20
- data/lib/bitcoin/protocol/version.rb +47 -34
- data/lib/bitcoin/script.rb +18 -17
- data/lib/bitcoin/trezor/mnemonic.rb +113 -98
- data/lib/bitcoin/version.rb +1 -1
- data/spec/examples.txt +399 -0
- data/spec/{bitcoin/fixtures → fixtures}/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/base58_keys_invalid.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/base58_keys_valid.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/coinbase-toshi.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/coinbase.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/filteredblock-0.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-170.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-9.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-auxpow.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-1151351.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-265322.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-01-toshi.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-02-toshi.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-03-toshi.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-04.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-05.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/script_tests.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/sighash.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +0 -0
- data/spec/{bitcoin/fixtures → fixtures}/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +0 -0
- data/spec/helpers/block_helpers.rb +58 -0
- data/spec/helpers/fixture_helpers.rb +20 -0
- data/spec/helpers/library_helpers.rb +15 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/unit/bitcoin/bech32_spec.rb +187 -0
- data/spec/unit/bitcoin/bitcoin_spec.rb +1079 -0
- data/spec/unit/bitcoin/bloom_filter_spec.rb +33 -0
- data/spec/unit/bitcoin/builder_spec.rb +559 -0
- data/spec/unit/bitcoin/contracthash_spec.rb +52 -0
- data/spec/unit/bitcoin/ext_key_spec.rb +281 -0
- data/spec/unit/bitcoin/key_spec.rb +457 -0
- data/spec/unit/bitcoin/network_spec.rb +71 -0
- data/spec/unit/bitcoin/protocol/addr_spec.rb +90 -0
- data/spec/unit/bitcoin/protocol/aux_pow_spec.rb +45 -0
- data/spec/unit/bitcoin/protocol/bip143_spec.rb +334 -0
- data/spec/unit/bitcoin/protocol/block_spec.rb +280 -0
- data/spec/unit/bitcoin/protocol/getblocks_spec.rb +44 -0
- data/spec/unit/bitcoin/protocol/inv_spec.rb +166 -0
- data/spec/unit/bitcoin/protocol/notfound_spec.rb +44 -0
- data/spec/unit/bitcoin/protocol/parser_spec.rb +69 -0
- data/spec/unit/bitcoin/protocol/partial_merkle_tree_spec.rb +47 -0
- data/spec/unit/bitcoin/protocol/ping_spec.rb +62 -0
- data/spec/unit/bitcoin/protocol/tx_spec.rb +1515 -0
- data/spec/unit/bitcoin/protocol/txin_spec.rb +47 -0
- data/spec/unit/bitcoin/protocol/txout_spec.rb +36 -0
- data/spec/unit/bitcoin/protocol/version_spec.rb +121 -0
- data/spec/unit/bitcoin/script/opcodes_spec.rb +864 -0
- data/spec/unit/bitcoin/script/script_spec.rb +1610 -0
- data/spec/unit/bitcoin/secp256k1_spec.rb +138 -0
- data/spec/unit/bitcoin/trezor/mnemonic_spec.rb +193 -0
- data/spec/unit/integrations/dogecoin_spec.rb +215 -0
- metadata +381 -372
- data/lib/bitcoin/logger.rb +0 -86
- data/lib/bitcoin/protocol/alert.rb +0 -46
- data/spec/bitcoin/bech32_spec.rb +0 -160
- data/spec/bitcoin/bitcoin_spec.rb +0 -666
- data/spec/bitcoin/bloom_filter_spec.rb +0 -23
- data/spec/bitcoin/builder_spec.rb +0 -375
- data/spec/bitcoin/contracthash_spec.rb +0 -45
- data/spec/bitcoin/dogecoin_spec.rb +0 -176
- data/spec/bitcoin/ext_key_spec.rb +0 -180
- data/spec/bitcoin/ffi_openssl.rb +0 -45
- data/spec/bitcoin/fixtures/rawblock-170.json +0 -68
- data/spec/bitcoin/fixtures/rawblock-9.json +0 -39
- data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
- data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
- data/spec/bitcoin/fixtures/txdp-1.txt +0 -32
- data/spec/bitcoin/fixtures/txdp-2-signed.txt +0 -19
- data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +0 -14
- data/spec/bitcoin/helpers/fake_blockchain.rb +0 -183
- data/spec/bitcoin/key_spec.rb +0 -326
- data/spec/bitcoin/network_spec.rb +0 -50
- data/spec/bitcoin/performance/storage_spec.rb +0 -41
- data/spec/bitcoin/protocol/addr_spec.rb +0 -82
- data/spec/bitcoin/protocol/alert_spec.rb +0 -22
- data/spec/bitcoin/protocol/aux_pow_spec.rb +0 -45
- data/spec/bitcoin/protocol/bip143_spec.rb +0 -116
- data/spec/bitcoin/protocol/block_spec.rb +0 -208
- data/spec/bitcoin/protocol/getblocks_spec.rb +0 -32
- data/spec/bitcoin/protocol/inv_spec.rb +0 -134
- data/spec/bitcoin/protocol/notfound_spec.rb +0 -31
- data/spec/bitcoin/protocol/parser_spec.rb +0 -50
- data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +0 -38
- data/spec/bitcoin/protocol/ping_spec.rb +0 -51
- data/spec/bitcoin/protocol/reject.rb +0 -17
- data/spec/bitcoin/protocol/tx_spec.rb +0 -894
- data/spec/bitcoin/protocol/txin_spec.rb +0 -45
- data/spec/bitcoin/protocol/txout_spec.rb +0 -33
- data/spec/bitcoin/protocol/version_spec.rb +0 -110
- data/spec/bitcoin/script/opcodes_spec.rb +0 -773
- data/spec/bitcoin/script/script_spec.rb +0 -977
- data/spec/bitcoin/secp256k1_spec.rb +0 -78
- data/spec/bitcoin/spec_helper.rb +0 -108
- 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
|