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.
- 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
|
@@ -1,61 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
module Bitcoin
|
|
2
|
+
module Protocol
|
|
3
|
+
# https://en.bitcoin.it/wiki/Protocol_documentation#Merkle_Trees
|
|
4
|
+
class PartialMerkleTree
|
|
5
|
+
Node = Struct.new(:value, :left, :right, :width_idx)
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
BIT_MASK = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80].freeze
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
def initialize(total_txs, hashes, flags)
|
|
10
|
+
@total_txs = total_txs
|
|
11
|
+
@flags = flags
|
|
12
|
+
@hashes = hashes.map(&:reverse_hth)
|
|
13
|
+
@visit_idx = 0
|
|
14
|
+
end
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
def tx_hashes
|
|
17
|
+
@leaves.reject { |n| n.value.nil? }.map(&:value)
|
|
18
|
+
end
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def build_tree
|
|
21
|
+
lay = @leaves = Array.new(@total_txs) { Node.new(nil, nil, nil) }
|
|
22
|
+
while lay.size > 1
|
|
23
|
+
lay = lay.each_slice(2).map do |left, right|
|
|
24
|
+
Node.new(nil, left, right)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
lay[0]
|
|
21
28
|
end
|
|
22
|
-
end
|
|
23
|
-
return lay[0]
|
|
24
|
-
end
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
def current_flag
|
|
31
|
+
(@flags[@visit_idx / 8].ord & BIT_MASK[@visit_idx % 8]).zero?
|
|
32
|
+
end
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
def root
|
|
35
|
+
@root ||= build_tree
|
|
36
|
+
end
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
def set_value(node = root) # rubocop:disable Naming/AccessorMethodName
|
|
39
|
+
warn '[DEPRECATION] `PartialMerkleTree.set_value` is deprecated. ' \
|
|
40
|
+
'Use `assign_value` instead.'
|
|
41
|
+
assign_value(node)
|
|
42
|
+
end
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@visit_idx += 1
|
|
46
|
-
set_value(node.right)
|
|
47
|
-
end
|
|
44
|
+
def assign_value(node = root)
|
|
45
|
+
if current_flag || (node.left.nil? && node.right.nil?)
|
|
46
|
+
node.value = @hashes.shift
|
|
47
|
+
return
|
|
48
|
+
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
if node.left
|
|
51
|
+
@visit_idx += 1
|
|
52
|
+
assign_value(node.left)
|
|
53
|
+
end
|
|
54
|
+
if node.right
|
|
55
|
+
@visit_idx += 1
|
|
56
|
+
assign_value(node.right)
|
|
57
|
+
end
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
right = node.right || node.left
|
|
60
|
+
node.value = Bitcoin.bitcoin_mrkl(node.left.value, right.value)
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def valid_tree?(mrkl_root_hash)
|
|
66
|
+
return false unless @hashes.empty?
|
|
67
|
+
return false if ((@visit_idx + 1) / 8.0).ceil != @flags.length
|
|
68
|
+
return false if mrkl_root_hash != root.value
|
|
69
|
+
true
|
|
70
|
+
end
|
|
71
|
+
end
|
|
60
72
|
end
|
|
61
73
|
end
|
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
3
|
module Bitcoin
|
|
4
|
-
module Protocol
|
|
4
|
+
module Protocol
|
|
5
|
+
Reject = Struct.new(:message, :ccode, :reason, :data) do
|
|
6
|
+
CCODE_TABLE = {
|
|
7
|
+
0x01 => :malformed,
|
|
8
|
+
0x10 => :invalid,
|
|
9
|
+
0x11 => :obsolete,
|
|
10
|
+
0x12 => :duplicate,
|
|
11
|
+
0x40 => :nonstandard,
|
|
12
|
+
0x41 => :dust,
|
|
13
|
+
0x42 => :insufficientfee,
|
|
14
|
+
0x43 => :checkpoint
|
|
15
|
+
}.freeze
|
|
5
16
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
0x12 => :duplicate,
|
|
12
|
-
0x40 => :nonstandard,
|
|
13
|
-
0x41 => :dust,
|
|
14
|
-
0x42 => :insufficientfee,
|
|
15
|
-
0x43 => :checkpoint,
|
|
16
|
-
}
|
|
17
|
+
def self.parse(payload)
|
|
18
|
+
message, payload = Bitcoin::Protocol.unpack_var_string(payload)
|
|
19
|
+
ccode, payload = payload.unpack('Ca*')
|
|
20
|
+
reason, payload = Bitcoin::Protocol.unpack_var_string(payload)
|
|
21
|
+
data = payload
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
reason, payload = Bitcoin::Protocol.unpack_var_string(payload)
|
|
22
|
-
data = payload
|
|
23
|
+
code = CCODE_TABLE[ccode] || ccode
|
|
24
|
+
new(message, code, reason, data)
|
|
25
|
+
end
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def tx_hash
|
|
29
|
-
message == "tx" && self[:data].reverse.bth
|
|
30
|
-
end
|
|
27
|
+
def tx_hash
|
|
28
|
+
message == 'tx' && self[:data].reverse.bth
|
|
29
|
+
end
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
def block_hash
|
|
32
|
+
message == 'block' && self[:data].reverse.bth
|
|
33
|
+
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
|
-
|
|
37
|
-
end
|
|
38
36
|
end
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
3
|
module Bitcoin
|
|
4
|
-
|
|
5
4
|
module Protocol
|
|
6
|
-
|
|
5
|
+
# TxWitness section of https://en.bitcoin.it/wiki/Protocol_documentation#tx
|
|
7
6
|
class ScriptWitness
|
|
8
|
-
|
|
9
7
|
# witness stack
|
|
10
8
|
attr_reader :stack
|
|
11
9
|
|
|
@@ -21,11 +19,8 @@ module Bitcoin
|
|
|
21
19
|
# output script in raw binary format
|
|
22
20
|
def to_payload
|
|
23
21
|
payload = Bitcoin::Protocol.pack_var_int(stack.size)
|
|
24
|
-
payload << stack.map{|e| Bitcoin::Protocol.pack_var_int(e.bytesize) << e }.join
|
|
22
|
+
payload << stack.map { |e| Bitcoin::Protocol.pack_var_int(e.bytesize) << e }.join
|
|
25
23
|
end
|
|
26
|
-
|
|
27
24
|
end
|
|
28
|
-
|
|
29
25
|
end
|
|
30
|
-
|
|
31
|
-
end
|
|
26
|
+
end
|
data/lib/bitcoin/protocol/tx.rb
CHANGED
|
@@ -4,9 +4,8 @@ require 'bitcoin/script'
|
|
|
4
4
|
|
|
5
5
|
module Bitcoin
|
|
6
6
|
module Protocol
|
|
7
|
-
|
|
7
|
+
# https://en.bitcoin.it/wiki/Protocol_documentation#tx
|
|
8
8
|
class Tx
|
|
9
|
-
|
|
10
9
|
MARKER = 0
|
|
11
10
|
FLAG = 1
|
|
12
11
|
|
|
@@ -36,8 +35,8 @@ module Bitcoin
|
|
|
36
35
|
attr_accessor :marker
|
|
37
36
|
attr_accessor :flag
|
|
38
37
|
|
|
39
|
-
alias
|
|
40
|
-
alias
|
|
38
|
+
alias inputs in
|
|
39
|
+
alias outputs out
|
|
41
40
|
|
|
42
41
|
# compare to another tx
|
|
43
42
|
def ==(other)
|
|
@@ -46,19 +45,23 @@ module Bitcoin
|
|
|
46
45
|
|
|
47
46
|
# return the tx hash in binary format
|
|
48
47
|
def binary_hash
|
|
49
|
-
@binary_hash ||= [@hash].pack(
|
|
48
|
+
@binary_hash ||= [@hash].pack('H*').reverse
|
|
50
49
|
end
|
|
51
50
|
|
|
52
51
|
# create tx from raw binary +data+
|
|
53
|
-
def initialize(data=nil)
|
|
54
|
-
@ver
|
|
55
|
-
@
|
|
52
|
+
def initialize(data = nil)
|
|
53
|
+
@ver = 1
|
|
54
|
+
@lock_time = 0
|
|
55
|
+
@in = []
|
|
56
|
+
@out = []
|
|
57
|
+
@scripts = []
|
|
58
|
+
@enable_bitcoinconsensus = !ENV['USE_BITCOINCONSENSUS'].nil?
|
|
56
59
|
parse_data_from_io(data) if data
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
# generate the tx hash for given +payload+ in hex format
|
|
60
63
|
def hash_from_payload(payload)
|
|
61
|
-
Digest::SHA256.digest(Digest::SHA256.digest(
|
|
64
|
+
Digest::SHA256.digest(Digest::SHA256.digest(payload)).reverse_hth
|
|
62
65
|
end
|
|
63
66
|
alias generate_hash hash_from_payload
|
|
64
67
|
|
|
@@ -68,26 +71,31 @@ module Bitcoin
|
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
# add an input
|
|
71
|
-
def add_in(input)
|
|
74
|
+
def add_in(input)
|
|
75
|
+
(@in ||= []) << input
|
|
76
|
+
end
|
|
72
77
|
|
|
73
78
|
# add an output
|
|
74
|
-
def add_out(output)
|
|
79
|
+
def add_out(output)
|
|
80
|
+
(@out ||= []) << output
|
|
81
|
+
end
|
|
75
82
|
|
|
76
83
|
# parse raw binary data
|
|
84
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
|
77
85
|
def parse_data_from_io(data)
|
|
78
86
|
buf = data.is_a?(String) ? StringIO.new(data) : data
|
|
79
87
|
|
|
80
|
-
@ver = buf.read(4).unpack(
|
|
88
|
+
@ver = buf.read(4).unpack('V')[0]
|
|
81
89
|
|
|
82
90
|
return false if buf.eof?
|
|
83
91
|
|
|
84
92
|
# segwit serialization format is defined by https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki
|
|
85
|
-
# Also note that it is impossible to parse 0 input transactions. Regular transactions
|
|
86
|
-
# like malformed segwit transactions.
|
|
93
|
+
# Also note that it is impossible to parse 0 input transactions. Regular transactions
|
|
94
|
+
# with 0 inputs look like malformed segwit transactions.
|
|
87
95
|
@marker = buf.read(1).unpack('c').first
|
|
88
96
|
@flag = buf.read(1).unpack('c').first
|
|
89
97
|
|
|
90
|
-
witness = @marker
|
|
98
|
+
witness = @marker.zero? && !@flag.zero?
|
|
91
99
|
|
|
92
100
|
# Non-segwit format does not contain marker or flag fields.
|
|
93
101
|
buf.seek(buf.pos - 2) unless witness
|
|
@@ -95,19 +103,19 @@ module Bitcoin
|
|
|
95
103
|
in_size = Protocol.unpack_var_int_from_io(buf)
|
|
96
104
|
|
|
97
105
|
@in = []
|
|
98
|
-
in_size.times
|
|
106
|
+
in_size.times do
|
|
99
107
|
break if buf.eof?
|
|
100
108
|
@in << TxIn.from_io(buf)
|
|
101
|
-
|
|
109
|
+
end
|
|
102
110
|
|
|
103
111
|
return false if buf.eof?
|
|
104
112
|
|
|
105
113
|
out_size = Protocol.unpack_var_int_from_io(buf)
|
|
106
114
|
@out = []
|
|
107
|
-
out_size.times
|
|
115
|
+
out_size.times do
|
|
108
116
|
break if buf.eof?
|
|
109
117
|
@out << TxOut.from_io(buf)
|
|
110
|
-
|
|
118
|
+
end
|
|
111
119
|
|
|
112
120
|
return false if buf.eof?
|
|
113
121
|
|
|
@@ -121,7 +129,7 @@ module Bitcoin
|
|
|
121
129
|
end
|
|
122
130
|
end
|
|
123
131
|
|
|
124
|
-
@lock_time = buf.read(4).unpack(
|
|
132
|
+
@lock_time = buf.read(4).unpack('V')[0]
|
|
125
133
|
|
|
126
134
|
@hash = hash_from_payload(to_old_payload)
|
|
127
135
|
@payload = to_payload
|
|
@@ -132,8 +140,9 @@ module Bitcoin
|
|
|
132
140
|
data.is_a?(StringIO) ? buf : buf.read
|
|
133
141
|
end
|
|
134
142
|
end
|
|
143
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
|
135
144
|
|
|
136
|
-
alias
|
|
145
|
+
alias parse_data parse_data_from_io
|
|
137
146
|
|
|
138
147
|
# output transaction in raw binary format
|
|
139
148
|
def to_payload
|
|
@@ -141,12 +150,14 @@ module Bitcoin
|
|
|
141
150
|
end
|
|
142
151
|
|
|
143
152
|
def to_old_payload
|
|
144
|
-
pin =
|
|
145
|
-
@in.each{|input| pin << input.to_payload }
|
|
146
|
-
pout =
|
|
147
|
-
@out.each{|output| pout << output.to_payload }
|
|
153
|
+
pin = ''
|
|
154
|
+
@in.each { |input| pin << input.to_payload }
|
|
155
|
+
pout = ''
|
|
156
|
+
@out.each { |output| pout << output.to_payload }
|
|
148
157
|
|
|
149
|
-
[@ver].pack(
|
|
158
|
+
[@ver].pack('V') << Protocol.pack_var_int(@in.size) \
|
|
159
|
+
<< pin << Protocol.pack_var_int(@out.size) \
|
|
160
|
+
<< pout << [@lock_time].pack('V')
|
|
150
161
|
end
|
|
151
162
|
|
|
152
163
|
# output transaction in raw binary format with witness
|
|
@@ -168,7 +179,10 @@ module Bitcoin
|
|
|
168
179
|
|
|
169
180
|
# generate a signature hash for input +input_idx+.
|
|
170
181
|
# either pass the +outpoint_tx+ or the +script_pubkey+ directly.
|
|
171
|
-
|
|
182
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
|
183
|
+
def signature_hash_for_input(
|
|
184
|
+
input_idx, subscript, hash_type = nil, prev_out_value = nil, fork_id = nil
|
|
185
|
+
)
|
|
172
186
|
# https://github.com/bitcoin/bitcoin/blob/e071a3f6c06f41068ad17134189a4ac3073ef76b/script.cpp#L834
|
|
173
187
|
# http://code.google.com/p/bitcoinj/source/browse/trunk/src/com/google/bitcoin/core/Script.java#318
|
|
174
188
|
# https://en.bitcoin.it/wiki/OP_CHECKSIG#How_it_works
|
|
@@ -181,31 +195,34 @@ module Bitcoin
|
|
|
181
195
|
# Bitcoin Cash protocol will be respected.
|
|
182
196
|
#
|
|
183
197
|
# https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/doc/abc/replay-protected-sighash.md
|
|
184
|
-
if fork_id && (hash_type&SIGHASH_TYPE[:forkid]) != 0
|
|
185
|
-
raise
|
|
198
|
+
if fork_id && (hash_type & SIGHASH_TYPE[:forkid]) != 0
|
|
199
|
+
raise 'SIGHASH_FORKID is enabled, so prev_out_value is required' if prev_out_value.nil?
|
|
186
200
|
|
|
187
201
|
# According to the spec, we should modify the sighash by replacing the 24 most significant
|
|
188
202
|
# bits with the fork ID. However, Bitcoin ABC does not currently implement this since the
|
|
189
203
|
# fork_id is an implicit 0 and it would make the sighash JSON tests fail. Will leave as a
|
|
190
204
|
# TODO for now.
|
|
191
|
-
raise NotImplementedError,
|
|
205
|
+
raise NotImplementedError, 'fork_id must be 0' unless fork_id.zero?
|
|
192
206
|
|
|
193
207
|
script_code = Bitcoin::Protocol.pack_var_string(subscript)
|
|
194
208
|
return signature_hash_for_input_bip143(input_idx, script_code, prev_out_value, hash_type)
|
|
195
209
|
end
|
|
196
210
|
|
|
197
211
|
# Note: BitcoinQT checks if input_idx >= @in.size and returns 1 with an error message.
|
|
198
|
-
# But this check is never actually useful because BitcoinQT would crash
|
|
199
|
-
#
|
|
212
|
+
# But this check is never actually useful because BitcoinQT would crash right before
|
|
213
|
+
# VerifyScript if input index is out of bounds (inside CScriptCheck::operator()()).
|
|
200
214
|
# That's why we don't need to do such a check here.
|
|
201
215
|
#
|
|
202
|
-
# However, if you look at the case SIGHASH_TYPE[:single] below, we must
|
|
203
|
-
#
|
|
204
|
-
return "\x01".ljust(32, "\x00") if input_idx >= @in.size # ERROR: SignatureHash() : input_idx=%d out of range
|
|
216
|
+
# However, if you look at the case SIGHASH_TYPE[:single] below, we must return 1
|
|
217
|
+
# because it's possible to have more inputs than outputs and BitcoinQT returns 1 as well.
|
|
205
218
|
|
|
206
|
-
|
|
219
|
+
# ERROR: SignatureHash() : input_idx=%d out of range
|
|
220
|
+
return "\x01".ljust(32, "\x00") if input_idx >= @in.size
|
|
221
|
+
|
|
222
|
+
pin = @in.map.with_index do |input, idx|
|
|
207
223
|
if idx == input_idx
|
|
208
|
-
|
|
224
|
+
# legacy api (outpoint_tx)
|
|
225
|
+
subscript = subscript.out[input.prev_out_index].script if subscript.respond_to?(:out)
|
|
209
226
|
|
|
210
227
|
# Remove all instances of OP_CODESEPARATOR from the script.
|
|
211
228
|
parsed_subscript = Script.new(subscript)
|
|
@@ -215,67 +232,93 @@ module Bitcoin
|
|
|
215
232
|
input.to_payload(subscript)
|
|
216
233
|
else
|
|
217
234
|
case (hash_type & 0x1f)
|
|
218
|
-
when SIGHASH_TYPE[:none]
|
|
219
|
-
when SIGHASH_TYPE[:single]
|
|
220
|
-
else;
|
|
235
|
+
when SIGHASH_TYPE[:none] then input.to_payload('', "\x00\x00\x00\x00")
|
|
236
|
+
when SIGHASH_TYPE[:single] then input.to_payload('', "\x00\x00\x00\x00")
|
|
237
|
+
else; input.to_payload('')
|
|
221
238
|
end
|
|
222
239
|
end
|
|
223
|
-
|
|
240
|
+
end
|
|
224
241
|
|
|
225
242
|
pout = @out.map(&:to_payload)
|
|
226
|
-
in_size
|
|
243
|
+
in_size = Protocol.pack_var_int(@in.size)
|
|
244
|
+
out_size = Protocol.pack_var_int(@out.size)
|
|
227
245
|
|
|
228
246
|
case (hash_type & 0x1f)
|
|
229
247
|
when SIGHASH_TYPE[:none]
|
|
230
|
-
pout =
|
|
248
|
+
pout = ''
|
|
231
249
|
out_size = Protocol.pack_var_int(0)
|
|
232
250
|
when SIGHASH_TYPE[:single]
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
251
|
+
# ERROR: SignatureHash() : input_idx=%d out of range (SIGHASH_SINGLE)
|
|
252
|
+
return "\x01".ljust(32, "\x00") if input_idx >= @out.size
|
|
253
|
+
|
|
254
|
+
pout = @out[0...(input_idx + 1)].map.with_index do |out, idx|
|
|
255
|
+
idx == input_idx ? out.to_payload : out.to_null_payload
|
|
256
|
+
end.join
|
|
257
|
+
|
|
258
|
+
out_size = Protocol.pack_var_int(input_idx + 1)
|
|
236
259
|
end
|
|
237
260
|
|
|
238
261
|
if (hash_type & SIGHASH_TYPE[:anyonecanpay]) != 0
|
|
239
|
-
in_size
|
|
262
|
+
in_size = Protocol.pack_var_int(1)
|
|
263
|
+
pin = [pin[input_idx]]
|
|
240
264
|
end
|
|
241
265
|
|
|
242
|
-
buf = [
|
|
243
|
-
|
|
266
|
+
buf = [
|
|
267
|
+
[@ver].pack('V'), in_size, pin, out_size,
|
|
268
|
+
pout, [@lock_time, hash_type].pack('VV')
|
|
269
|
+
].join
|
|
270
|
+
Digest::SHA256.digest(Digest::SHA256.digest(buf))
|
|
244
271
|
end
|
|
272
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
|
245
273
|
|
|
246
274
|
# generate a witness signature hash for input +input_idx+.
|
|
247
275
|
# https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
|
|
248
|
-
|
|
249
|
-
|
|
276
|
+
# rubocop:disable Metrics/ParameterLists
|
|
277
|
+
def signature_hash_for_witness_input(
|
|
278
|
+
input_idx, witness_program, prev_out_value,
|
|
279
|
+
witness_script = nil, hash_type = nil, skip_separator_index = 0
|
|
280
|
+
)
|
|
281
|
+
# ERROR: SignatureHash() : input_idx=%d out of range
|
|
282
|
+
return "\x01".ljust(32, "\x00") if input_idx >= @in.size
|
|
250
283
|
|
|
251
284
|
hash_type ||= SIGHASH_TYPE[:all]
|
|
252
|
-
|
|
253
285
|
script = Bitcoin::Script.new(witness_program)
|
|
254
|
-
raise
|
|
286
|
+
raise 'ScriptPubkey does not contain witness program.' unless script.is_witness?
|
|
255
287
|
|
|
256
288
|
if script.is_witness_v0_keyhash?
|
|
257
|
-
script_code = [[
|
|
289
|
+
script_code = [['1976a914', script.get_hash160, '88ac'].join].pack('H*')
|
|
258
290
|
elsif script.is_witness_v0_scripthash?
|
|
259
|
-
|
|
260
|
-
|
|
291
|
+
witness_pubkey_script_match = Bitcoin::Script.to_witness_p2sh_script(
|
|
292
|
+
Digest::SHA256.digest(witness_script).bth
|
|
293
|
+
) == witness_program
|
|
294
|
+
raise 'witness script does not match script pubkey' unless witness_pubkey_script_match
|
|
295
|
+
|
|
296
|
+
script = if skip_separator_index > 0
|
|
297
|
+
s = Bitcoin::Script.new(witness_script)
|
|
298
|
+
s.subscript_codeseparator(skip_separator_index)
|
|
299
|
+
else
|
|
300
|
+
witness_script
|
|
301
|
+
end
|
|
261
302
|
script_code = Bitcoin::Protocol.pack_var_string(script)
|
|
262
303
|
end
|
|
263
304
|
|
|
264
305
|
signature_hash_for_input_bip143(input_idx, script_code, prev_out_value, hash_type)
|
|
265
306
|
end
|
|
307
|
+
# rubocop:enable Metrics/ParameterLists
|
|
266
308
|
|
|
267
309
|
# verify input signature +in_idx+ against the corresponding
|
|
268
310
|
# output in +outpoint_tx+
|
|
269
311
|
# outpoint. This arg can also be a Script or TxOut.
|
|
270
312
|
#
|
|
271
|
-
# options are: verify_sigpushonly, verify_minimaldata, verify_cleanstack,
|
|
272
|
-
|
|
313
|
+
# options are: verify_sigpushonly, verify_minimaldata, verify_cleanstack,
|
|
314
|
+
# verify_dersig, verify_low_s, verify_strictenc, fork_id
|
|
315
|
+
def verify_input_signature(in_idx, outpoint_data, block_timestamp = Time.now.to_i, opts = {})
|
|
273
316
|
if @enable_bitcoinconsensus
|
|
274
317
|
return bitcoinconsensus_verify_script(in_idx, outpoint_data, block_timestamp, opts)
|
|
275
318
|
end
|
|
276
319
|
|
|
277
320
|
# If FORKID is enabled, we also ensure strict encoding.
|
|
278
|
-
opts[:verify_strictenc] ||=
|
|
321
|
+
opts[:verify_strictenc] ||= !opts[:fork_id].nil?
|
|
279
322
|
|
|
280
323
|
outpoint_idx = @in[in_idx].prev_out_index
|
|
281
324
|
script_sig = @in[in_idx].script_sig
|
|
@@ -284,29 +327,36 @@ module Bitcoin
|
|
|
284
327
|
script_pubkey = script_pubkey_from_outpoint_data(outpoint_data, outpoint_idx)
|
|
285
328
|
|
|
286
329
|
if opts[:fork_id] && amount.nil?
|
|
287
|
-
raise
|
|
288
|
-
|
|
330
|
+
raise 'verify_input_signature must be called with a previous transaction or ' \
|
|
331
|
+
'transaction output if SIGHASH_FORKID is enabled'
|
|
289
332
|
end
|
|
290
333
|
|
|
291
334
|
@scripts[in_idx] = Bitcoin::Script.new(script_sig, script_pubkey)
|
|
292
335
|
return false if opts[:verify_sigpushonly] && !@scripts[in_idx].is_push_only?(script_sig)
|
|
293
336
|
return false if opts[:verify_minimaldata] && !@scripts[in_idx].pushes_are_canonical?
|
|
294
|
-
sig_valid = @scripts[in_idx].run(
|
|
337
|
+
sig_valid = @scripts[in_idx].run(
|
|
338
|
+
block_timestamp, opts
|
|
339
|
+
) do |pubkey, sig, hash_type, subscript|
|
|
295
340
|
hash = signature_hash_for_input(in_idx, subscript, hash_type, amount, opts[:fork_id])
|
|
296
|
-
Bitcoin.verify_signature(
|
|
341
|
+
Bitcoin.verify_signature(hash, sig, pubkey.unpack('H*')[0])
|
|
297
342
|
end
|
|
298
343
|
# BIP62 rule #6
|
|
299
344
|
return false if opts[:verify_cleanstack] && !@scripts[in_idx].stack.empty?
|
|
300
345
|
|
|
301
|
-
|
|
346
|
+
sig_valid
|
|
302
347
|
end
|
|
303
348
|
|
|
304
349
|
# verify witness input signature +in_idx+ against the corresponding
|
|
305
350
|
# output in +outpoint_tx+
|
|
306
351
|
# outpoint. This arg can also be a Script or TxOut
|
|
307
352
|
#
|
|
308
|
-
# options are: verify_sigpushonly, verify_minimaldata, verify_cleanstack,
|
|
309
|
-
|
|
353
|
+
# options are: verify_sigpushonly, verify_minimaldata, verify_cleanstack,
|
|
354
|
+
# verify_dersig, verify_low_s, verify_strictenc
|
|
355
|
+
#
|
|
356
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
|
357
|
+
def verify_witness_input_signature(
|
|
358
|
+
in_idx, outpoint_data, prev_out_amount, block_timestamp = Time.now.to_i, opts = {}
|
|
359
|
+
)
|
|
310
360
|
if @enable_bitcoinconsensus
|
|
311
361
|
return bitcoinconsensus_verify_script(in_idx, outpoint_data, block_timestamp, opts)
|
|
312
362
|
end
|
|
@@ -319,52 +369,69 @@ module Bitcoin
|
|
|
319
369
|
|
|
320
370
|
if script_pubkey.is_p2sh?
|
|
321
371
|
redeem_script = Bitcoin::Script.new(@in[in_idx].script_sig).get_pubkey
|
|
322
|
-
|
|
372
|
+
|
|
373
|
+
# P2SH-P2WPKH or P2SH-P2WSH
|
|
374
|
+
script_pubkey = if Bitcoin.hash160(redeem_script) == script_pubkey.get_hash160
|
|
375
|
+
Bitcoin::Script.new(redeem_script.htb)
|
|
376
|
+
end
|
|
323
377
|
end
|
|
324
378
|
|
|
325
|
-
@in[in_idx].script_witness.stack.each{|s|script_sig << Bitcoin::Script.pack_pushdata(s)}
|
|
379
|
+
@in[in_idx].script_witness.stack.each { |s| script_sig << Bitcoin::Script.pack_pushdata(s) }
|
|
326
380
|
code_separator_index = 0
|
|
327
381
|
|
|
328
382
|
if script_pubkey.is_witness_v0_keyhash? # P2WPKH
|
|
329
|
-
@scripts[in_idx] = Bitcoin::Script.new(
|
|
383
|
+
@scripts[in_idx] = Bitcoin::Script.new(
|
|
384
|
+
script_sig, Bitcoin::Script.to_hash160_script(script_pubkey.get_hash160)
|
|
385
|
+
)
|
|
330
386
|
elsif script_pubkey.is_witness_v0_scripthash? # P2WSH
|
|
331
387
|
witness_hex = @in[in_idx].script_witness.stack.last.bth
|
|
332
388
|
witness_script = Bitcoin::Script.new(witness_hex.htb)
|
|
333
389
|
return false unless Bitcoin.sha256(witness_hex) == script_pubkey.get_hash160
|
|
334
|
-
@scripts[in_idx] = Bitcoin::Script.new(
|
|
390
|
+
@scripts[in_idx] = Bitcoin::Script.new(
|
|
391
|
+
script_sig, Bitcoin::Script.to_p2sh_script(Bitcoin.hash160(witness_hex))
|
|
392
|
+
)
|
|
335
393
|
else
|
|
336
394
|
return false
|
|
337
395
|
end
|
|
338
396
|
|
|
339
397
|
return false if opts[:verify_sigpushonly] && !@scripts[in_idx].is_push_only?(script_sig)
|
|
340
398
|
return false if opts[:verify_minimaldata] && !@scripts[in_idx].pushes_are_canonical?
|
|
341
|
-
sig_valid = @scripts[in_idx].run(block_timestamp, opts) do |pubkey,sig,hash_type,
|
|
399
|
+
sig_valid = @scripts[in_idx].run(block_timestamp, opts) do |pubkey, sig, hash_type, _|
|
|
342
400
|
if script_pubkey.is_witness_v0_keyhash?
|
|
343
|
-
hash = signature_hash_for_witness_input(
|
|
401
|
+
hash = signature_hash_for_witness_input(
|
|
402
|
+
in_idx, script_pubkey.to_payload, prev_out_amount, nil, hash_type
|
|
403
|
+
)
|
|
344
404
|
elsif script_pubkey.is_witness_v0_scripthash?
|
|
345
|
-
hash = signature_hash_for_witness_input(
|
|
405
|
+
hash = signature_hash_for_witness_input(
|
|
406
|
+
in_idx, script_pubkey.to_payload, prev_out_amount,
|
|
407
|
+
witness_hex.htb, hash_type, code_separator_index
|
|
408
|
+
)
|
|
346
409
|
code_separator_index += 1 if witness_script.codeseparator_count > code_separator_index
|
|
347
410
|
end
|
|
348
|
-
Bitcoin.verify_signature(
|
|
411
|
+
Bitcoin.verify_signature(hash, sig, pubkey.unpack('H*')[0])
|
|
349
412
|
end
|
|
350
413
|
# BIP62 rule #6
|
|
351
414
|
return false if opts[:verify_cleanstack] && !@scripts[in_idx].stack.empty?
|
|
352
415
|
|
|
353
|
-
|
|
416
|
+
sig_valid
|
|
354
417
|
end
|
|
418
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
|
355
419
|
|
|
356
|
-
def bitcoinconsensus_verify_script(
|
|
357
|
-
|
|
420
|
+
def bitcoinconsensus_verify_script(
|
|
421
|
+
in_idx, outpoint_data, block_timestamp = Time.now.to_i, opts = {}
|
|
422
|
+
)
|
|
423
|
+
consensus_available = Bitcoin::BitcoinConsensus.lib_available?
|
|
424
|
+
raise 'Bitcoin::BitcoinConsensus shared library not found' unless consensus_available
|
|
358
425
|
|
|
359
426
|
outpoint_idx = @in[in_idx].prev_out_index
|
|
360
427
|
script_pubkey = script_pubkey_from_outpoint_data(outpoint_data, outpoint_idx)
|
|
361
428
|
|
|
362
429
|
flags = Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_NONE
|
|
363
|
-
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_P2SH
|
|
430
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_P2SH if block_timestamp >= 1_333_238_400
|
|
364
431
|
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_SIGPUSHONLY if opts[:verify_sigpushonly]
|
|
365
432
|
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_MINIMALDATA if opts[:verify_minimaldata]
|
|
366
|
-
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_CLEANSTACK
|
|
367
|
-
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_LOW_S
|
|
433
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_CLEANSTACK if opts[:verify_cleanstack]
|
|
434
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_LOW_S if opts[:verify_low_s]
|
|
368
435
|
|
|
369
436
|
payload ||= to_payload
|
|
370
437
|
Bitcoin::BitcoinConsensus.verify_script(in_idx, script_pubkey, payload, flags)
|
|
@@ -377,38 +444,37 @@ module Bitcoin
|
|
|
377
444
|
'hash' => @hash, 'ver' => @ver, # 'nid' => normalized_hash,
|
|
378
445
|
'vin_sz' => @in.size, 'vout_sz' => @out.size,
|
|
379
446
|
'lock_time' => @lock_time, 'size' => (@payload ||= to_payload).bytesize,
|
|
380
|
-
'in' => @in.map{|i|i.to_hash(options)},
|
|
381
|
-
'out' => @out.map{|o| o.to_hash(options) }
|
|
447
|
+
'in' => @in.map { |i| i.to_hash(options) },
|
|
448
|
+
'out' => @out.map { |o| o.to_hash(options) }
|
|
382
449
|
}
|
|
383
|
-
h['nid'] = normalized_hash
|
|
450
|
+
h['nid'] = normalized_hash if options[:with_nid]
|
|
384
451
|
h
|
|
385
452
|
end
|
|
386
453
|
|
|
387
454
|
# generates rawblock json as seen in the block explorer.
|
|
388
|
-
def to_json(options = {:
|
|
389
|
-
JSON.pretty_generate(
|
|
455
|
+
def to_json(options = { space: '' }, *_a)
|
|
456
|
+
JSON.pretty_generate(to_hash(options), options)
|
|
390
457
|
end
|
|
391
458
|
|
|
392
459
|
# write json representation to a file
|
|
393
460
|
# (see also #to_json)
|
|
394
461
|
def to_json_file(path)
|
|
395
|
-
File.open(path, 'wb'){|f| f.print to_json; }
|
|
462
|
+
File.open(path, 'wb') { |f| f.print to_json; }
|
|
396
463
|
end
|
|
397
464
|
|
|
398
465
|
# parse ruby hash (see also #to_hash)
|
|
399
|
-
def self.from_hash(h, do_raise=true)
|
|
466
|
+
def self.from_hash(h, do_raise = true)
|
|
400
467
|
tx = new(nil)
|
|
401
|
-
tx.ver
|
|
468
|
+
tx.ver = (h['ver'] || h['version'])
|
|
469
|
+
tx.lock_time = h['lock_time']
|
|
402
470
|
ins = h['in'] || h['inputs']
|
|
403
471
|
outs = h['out'] || h['outputs']
|
|
404
|
-
ins
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
outs.each{|output| tx.add_out TxOut.from_hash(output) }
|
|
408
|
-
tx.instance_eval{
|
|
472
|
+
ins.each { |input| tx.add_in(TxIn.from_hash(input)) }
|
|
473
|
+
outs.each { |output| tx.add_out TxOut.from_hash(output) }
|
|
474
|
+
tx.instance_eval do
|
|
409
475
|
@hash = hash_from_payload(to_old_payload)
|
|
410
476
|
@payload = to_payload
|
|
411
|
-
|
|
477
|
+
end
|
|
412
478
|
if h['hash'] && (h['hash'] != tx.hash)
|
|
413
479
|
raise "Tx hash mismatch! Claimed: #{h['hash']}, Actual: #{tx.hash}" if do_raise
|
|
414
480
|
end
|
|
@@ -422,61 +488,86 @@ module Bitcoin
|
|
|
422
488
|
end
|
|
423
489
|
|
|
424
490
|
# parse json representation
|
|
425
|
-
def self.from_json(json_string)
|
|
491
|
+
def self.from_json(json_string)
|
|
492
|
+
from_hash(JSON.parse(json_string))
|
|
493
|
+
end
|
|
426
494
|
|
|
427
495
|
# convert json representation to raw binary
|
|
428
|
-
def self.binary_from_json(json_string)
|
|
496
|
+
def self.binary_from_json(json_string)
|
|
497
|
+
from_json(json_string).to_payload
|
|
498
|
+
end
|
|
429
499
|
|
|
430
500
|
# read binary block from a file
|
|
431
|
-
def self.from_file(path)
|
|
501
|
+
def self.from_file(path)
|
|
502
|
+
new(Bitcoin::Protocol.read_binary_file(path))
|
|
503
|
+
end
|
|
432
504
|
|
|
433
505
|
# read json block from a file
|
|
434
|
-
def self.from_json_file(path)
|
|
506
|
+
def self.from_json_file(path)
|
|
507
|
+
from_json(Bitcoin::Protocol.read_binary_file(path))
|
|
508
|
+
end
|
|
435
509
|
|
|
436
510
|
def size
|
|
437
511
|
payload.bytesize
|
|
438
512
|
end
|
|
439
|
-
|
|
440
|
-
|
|
513
|
+
|
|
514
|
+
def is_final?(block_height, block_time) # rubocop:disable Naming/PredicateName
|
|
515
|
+
warn '[DEPRECATION] `Tx.is_final?` is deprecated. Use `final?` instead.'
|
|
516
|
+
final?(block_height, block_time)
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# Checks if transaction is final taking into account height and time
|
|
441
520
|
# of a block in which it is located (or about to be included if it's unconfirmed tx).
|
|
442
|
-
def
|
|
521
|
+
def final?(block_height, block_time)
|
|
443
522
|
# No time lock - tx is final.
|
|
444
|
-
return true if lock_time
|
|
523
|
+
return true if lock_time.zero?
|
|
445
524
|
|
|
446
525
|
# Time based nLockTime implemented in 0.1.6
|
|
447
526
|
# If lock_time is below the magic threshold treat it as a block height.
|
|
448
527
|
# If lock_time is above the threshold, it's a unix timestamp.
|
|
449
|
-
|
|
528
|
+
lock_threshold = lock_time < Bitcoin::LOCKTIME_THRESHOLD ? block_height : block_time
|
|
529
|
+
return true if lock_time < lock_threshold
|
|
450
530
|
|
|
451
|
-
inputs.each{|input| return false
|
|
531
|
+
inputs.each { |input| return false unless input.final? }
|
|
452
532
|
|
|
453
|
-
|
|
533
|
+
true
|
|
454
534
|
end
|
|
455
|
-
|
|
535
|
+
|
|
456
536
|
def legacy_sigops_count
|
|
457
|
-
# Note: input scripts normally never have any opcodes since every input script
|
|
537
|
+
# Note: input scripts normally never have any opcodes since every input script
|
|
458
538
|
# can be statically reduced to a pushdata-only script.
|
|
459
|
-
# However, anyone is allowed to create a non-standard transaction
|
|
539
|
+
# However, anyone is allowed to create a non-standard transaction
|
|
540
|
+
# with any opcodes in the inputs.
|
|
460
541
|
count = 0
|
|
461
542
|
self.in.each do |txin|
|
|
462
543
|
count += Bitcoin::Script.new(txin.script_sig).sigops_count_accurate(false)
|
|
463
544
|
end
|
|
464
|
-
|
|
545
|
+
out.each do |txout|
|
|
465
546
|
count += Bitcoin::Script.new(txout.pk_script).sigops_count_accurate(false)
|
|
466
547
|
end
|
|
467
548
|
count
|
|
468
549
|
end
|
|
469
550
|
|
|
470
|
-
DEFAULT_BLOCK_PRIORITY_SIZE =
|
|
551
|
+
DEFAULT_BLOCK_PRIORITY_SIZE = 27_000
|
|
471
552
|
|
|
472
|
-
def minimum_relay_fee
|
|
473
|
-
|
|
553
|
+
def minimum_relay_fee
|
|
554
|
+
calculate_minimum_fee(true, :relay)
|
|
555
|
+
end
|
|
474
556
|
|
|
475
|
-
def
|
|
557
|
+
def minimum_block_fee
|
|
558
|
+
calculate_minimum_fee(true, :block)
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
# rubocop:disable PerceivedComplexity
|
|
562
|
+
def calculate_minimum_fee(allow_free = true, mode = :block)
|
|
476
563
|
# Base fee is either nMinTxFee or nMinRelayTxFee
|
|
477
|
-
base_fee
|
|
478
|
-
|
|
479
|
-
|
|
564
|
+
base_fee = if mode == :relay
|
|
565
|
+
Bitcoin.network[:min_relay_tx_fee]
|
|
566
|
+
else
|
|
567
|
+
Bitcoin.network[:min_tx_fee]
|
|
568
|
+
end
|
|
569
|
+
tx_size = to_payload.bytesize
|
|
570
|
+
min_fee = (1 + tx_size / 1_000) * base_fee
|
|
480
571
|
|
|
481
572
|
if allow_free
|
|
482
573
|
# There is a free transaction area in blocks created by most miners,
|
|
@@ -485,7 +576,12 @@ module Bitcoin
|
|
|
485
576
|
# multiple transactions instead of one big transaction to avoid fees.
|
|
486
577
|
# * If we are creating a transaction we allow transactions up to 1,000 bytes
|
|
487
578
|
# to be considered safe and assume they can likely make it into this section.
|
|
488
|
-
|
|
579
|
+
min_free_size = if mode == :block
|
|
580
|
+
Bitcoin.network[:free_tx_bytes]
|
|
581
|
+
else
|
|
582
|
+
DEFAULT_BLOCK_PRIORITY_SIZE - 1_000
|
|
583
|
+
end
|
|
584
|
+
min_fee = 0 if tx_size < min_free_size
|
|
489
585
|
end
|
|
490
586
|
|
|
491
587
|
# This code can be removed after enough miners have upgraded to version 0.9.
|
|
@@ -505,18 +601,27 @@ module Bitcoin
|
|
|
505
601
|
end
|
|
506
602
|
end
|
|
507
603
|
|
|
508
|
-
min_fee = Bitcoin
|
|
604
|
+
min_fee = Bitcoin.network[:max_money] unless min_fee.between?(
|
|
605
|
+
0, Bitcoin.network[:max_money]
|
|
606
|
+
)
|
|
509
607
|
min_fee
|
|
510
608
|
end
|
|
609
|
+
# rubocop:enable PerceivedComplexity
|
|
511
610
|
|
|
512
|
-
def is_coinbase?
|
|
513
|
-
|
|
611
|
+
def is_coinbase? # rubocop:disable Naming/PredicateName
|
|
612
|
+
warn '[DEPRECATION] `Tx.is_coinbase?` is deprecated. Use `coinbase?` instead.'
|
|
613
|
+
coinbase?
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def coinbase?
|
|
617
|
+
inputs.size == 1 && inputs.first.coinbase?
|
|
514
618
|
end
|
|
515
619
|
|
|
516
620
|
def normalized_hash
|
|
517
621
|
signature_hash_for_input(-1, nil, SIGHASH_TYPE[:all]).reverse.hth
|
|
518
622
|
end
|
|
519
|
-
|
|
623
|
+
|
|
624
|
+
alias nhash normalized_hash
|
|
520
625
|
|
|
521
626
|
# get witness hash
|
|
522
627
|
def witness_hash
|
|
@@ -526,37 +631,45 @@ module Bitcoin
|
|
|
526
631
|
# sort transaction inputs and outputs under BIP 69
|
|
527
632
|
# https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
|
|
528
633
|
def lexicographical_sort!
|
|
529
|
-
inputs.sort_by!{|i| [i.previous_output, i.prev_out_index]}
|
|
530
|
-
outputs.sort_by!{|o| [o.amount, o.pk_script.bth]}
|
|
634
|
+
inputs.sort_by! { |i| [i.previous_output, i.prev_out_index] }
|
|
635
|
+
outputs.sort_by! { |o| [o.amount, o.pk_script.bth] }
|
|
531
636
|
end
|
|
532
637
|
|
|
533
638
|
private
|
|
534
639
|
|
|
535
640
|
def signature_hash_for_input_bip143(input_idx, script_code, prev_out_value, hash_type)
|
|
536
|
-
hash_prevouts = Digest::SHA256.digest(
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
641
|
+
hash_prevouts = Digest::SHA256.digest(
|
|
642
|
+
Digest::SHA256.digest(
|
|
643
|
+
@in.map { |i| [i.prev_out_hash, i.prev_out_index].pack('a32V') }.join
|
|
644
|
+
)
|
|
645
|
+
)
|
|
646
|
+
hash_sequence = Digest::SHA256.digest(Digest::SHA256.digest(@in.map(&:sequence).join))
|
|
647
|
+
outpoint = [@in[input_idx].prev_out_hash, @in[input_idx].prev_out_index].pack('a32V')
|
|
648
|
+
amount = [prev_out_value].pack('Q')
|
|
540
649
|
nsequence = @in[input_idx].sequence
|
|
541
650
|
|
|
542
|
-
hash_outputs = Digest::SHA256.digest(Digest::SHA256.digest(@out.map
|
|
651
|
+
hash_outputs = Digest::SHA256.digest(Digest::SHA256.digest(@out.map(&:to_payload).join))
|
|
543
652
|
|
|
544
653
|
case (hash_type & 0x1f)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
654
|
+
when SIGHASH_TYPE[:single]
|
|
655
|
+
hash_outputs = if input_idx >= @out.size
|
|
656
|
+
"\x00".ljust(32, "\x00")
|
|
657
|
+
else
|
|
658
|
+
Digest::SHA256.digest(Digest::SHA256.digest(@out[input_idx].to_payload))
|
|
659
|
+
end
|
|
660
|
+
hash_sequence = "\x00".ljust(32, "\x00")
|
|
661
|
+
when SIGHASH_TYPE[:none]
|
|
662
|
+
hash_sequence = hash_outputs = "\x00".ljust(32, "\x00")
|
|
550
663
|
end
|
|
551
664
|
|
|
552
665
|
if (hash_type & SIGHASH_TYPE[:anyonecanpay]) != 0
|
|
553
|
-
hash_prevouts = hash_sequence ="\x00".ljust(32, "\x00")
|
|
666
|
+
hash_prevouts = hash_sequence = "\x00".ljust(32, "\x00")
|
|
554
667
|
end
|
|
555
668
|
|
|
556
|
-
buf = [
|
|
557
|
-
|
|
669
|
+
buf = [[@ver].pack('V'), hash_prevouts, hash_sequence, outpoint, script_code,
|
|
670
|
+
amount, nsequence, hash_outputs, [@lock_time, hash_type].pack('VV')].join
|
|
558
671
|
|
|
559
|
-
Digest::SHA256.digest(
|
|
672
|
+
Digest::SHA256.digest(Digest::SHA256.digest(buf))
|
|
560
673
|
end
|
|
561
674
|
|
|
562
675
|
def script_pubkey_from_outpoint_data(outpoint_data, outpoint_idx)
|