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
data/lib/bitcoin/bech32.rb
CHANGED
@@ -1,172 +1,166 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
|
-
|
3
|
-
module Bitcoin
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
return ((pre & 0x1FFFFFF) << 5) ^ \
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
# Ruby reference implementation: https://github.com/sipa/bech32/tree/master/ref/c
|
5
|
+
module Bech32
|
6
|
+
CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'.unpack('C*')
|
7
|
+
CHARSET_REV = [
|
8
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
9
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
10
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
11
|
+
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
12
|
+
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
13
|
+
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
14
|
+
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
15
|
+
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def polymod_step(pre)
|
20
|
+
b = pre >> 25
|
21
|
+
((pre & 0x1FFFFFF) << 5) ^ \
|
23
22
|
(-((b >> 0) & 1) & 0x3b6a57b2) ^ \
|
24
23
|
(-((b >> 1) & 1) & 0x26508e6d) ^ \
|
25
24
|
(-((b >> 2) & 1) & 0x1ea119fa) ^ \
|
26
25
|
(-((b >> 3) & 1) & 0x3d4233dd) ^ \
|
27
26
|
(-((b >> 4) & 1) & 0x2a1462b3)
|
28
|
-
end
|
29
|
-
|
30
|
-
def encode(hrp, data)
|
31
|
-
buf = []
|
32
|
-
chk = 1
|
33
|
-
|
34
|
-
hrp.unpack("C*").each do |ch|
|
35
|
-
return nil if ch < 33 || ch > 126
|
36
|
-
return nil if ch >= 'A'.ord && ch <= 'Z'.ord
|
37
|
-
chk = polymod_step(chk) ^ (ch >> 5)
|
38
27
|
end
|
39
28
|
|
40
|
-
|
29
|
+
def encode(hrp, data)
|
30
|
+
buf = []
|
31
|
+
chk = 1
|
41
32
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
buf << '1'.ord
|
33
|
+
hrp.unpack('C*').each do |ch|
|
34
|
+
return nil if ch < 33 || ch > 126
|
35
|
+
return nil if ch >= 'A'.ord && ch <= 'Z'.ord
|
36
|
+
chk = polymod_step(chk) ^ (ch >> 5)
|
37
|
+
end
|
49
38
|
|
50
|
-
|
51
|
-
return nil if (i >> 5) != 0
|
52
|
-
chk = polymod_step(chk) ^ i
|
53
|
-
buf << CHARSET[i]
|
54
|
-
end
|
39
|
+
return nil if (hrp.bytesize + 7 + data.size) > 90
|
55
40
|
|
56
|
-
6.times do |n|
|
57
41
|
chk = polymod_step(chk)
|
58
|
-
|
42
|
+
hrp.unpack('C*').each do |ch|
|
43
|
+
chk = polymod_step(chk) ^ (ch & 0x1f)
|
44
|
+
buf << ch
|
45
|
+
end
|
59
46
|
|
60
|
-
|
47
|
+
buf << '1'.ord
|
61
48
|
|
62
|
-
|
63
|
-
|
64
|
-
|
49
|
+
data.each do |i|
|
50
|
+
return nil if (i >> 5) != 0
|
51
|
+
chk = polymod_step(chk) ^ i
|
52
|
+
buf << CHARSET[i]
|
53
|
+
end
|
65
54
|
|
66
|
-
|
67
|
-
|
55
|
+
6.times do
|
56
|
+
chk = polymod_step(chk)
|
57
|
+
end
|
68
58
|
|
69
|
-
|
70
|
-
chk = 1
|
71
|
-
input_len = input.bytesize
|
72
|
-
have_lower, have_upper = false, false
|
59
|
+
chk ^= 1
|
73
60
|
|
74
|
-
|
61
|
+
6.times do |i|
|
62
|
+
buf << CHARSET[(chk >> ((5 - i) * 5)) & 0x1f]
|
63
|
+
end
|
75
64
|
|
76
|
-
|
77
|
-
while data_len < input_len && input[(input_len - 1) - data_len] != '1' do
|
78
|
-
data_len += 1
|
65
|
+
buf.pack('C*')
|
79
66
|
end
|
80
67
|
|
81
|
-
|
82
|
-
|
68
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
69
|
+
def decode(input)
|
70
|
+
chk = 1
|
71
|
+
input_len = input.bytesize
|
72
|
+
have_lower = false
|
73
|
+
have_upper = false
|
83
74
|
|
84
|
-
|
75
|
+
return nil if input_len < 8 || input_len > 90
|
85
76
|
|
86
|
-
|
87
|
-
|
88
|
-
ch = input[i].ord
|
89
|
-
return nil if ch < 33 || ch > 126
|
77
|
+
data_len = 0
|
78
|
+
data_len += 1 while data_len < input_len && input[(input_len - 1) - data_len] != '1'
|
90
79
|
|
91
|
-
|
92
|
-
|
93
|
-
elsif ch >= 'A'.ord && ch <= 'Z'.ord
|
94
|
-
have_upper = true
|
95
|
-
ch = (ch - 'A'.ord) + 'a'.ord
|
96
|
-
end
|
80
|
+
hrp_len = input_len - (1 + data_len)
|
81
|
+
return nil if hrp_len < 1 || data_len < 6
|
97
82
|
|
98
|
-
hrp
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
chk = polymod_step(chk)
|
83
|
+
hrp = []
|
84
|
+
hrp_len.times do |i|
|
85
|
+
ch = input[i].ord
|
86
|
+
return nil if ch < 33 || ch > 126
|
103
87
|
|
104
|
-
|
105
|
-
|
106
|
-
|
88
|
+
if ch >= 'a'.ord && ch <= 'z'.ord
|
89
|
+
have_lower = true
|
90
|
+
elsif ch >= 'A'.ord && ch <= 'Z'.ord
|
91
|
+
have_upper = true
|
92
|
+
ch = (ch - 'A'.ord) + 'a'.ord
|
93
|
+
end
|
107
94
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
ch = input[i].ord
|
112
|
-
v = ((ch & 0x80) != 0) ? -1 : CHARSET_REV[ch]
|
95
|
+
hrp << ch
|
96
|
+
chk = polymod_step(chk) ^ (ch >> 5)
|
97
|
+
end
|
113
98
|
|
114
|
-
|
115
|
-
have_upper = true if ch >= 'A'.ord && ch <= 'Z'.ord
|
116
|
-
return nil if v == -1
|
99
|
+
chk = polymod_step(chk)
|
117
100
|
|
118
|
-
|
119
|
-
|
120
|
-
data << v
|
101
|
+
hrp_len.times do |i|
|
102
|
+
chk = polymod_step(chk) ^ (input[i].ord & 0x1f)
|
121
103
|
end
|
122
|
-
i += 1
|
123
|
-
end
|
124
104
|
|
125
|
-
|
126
|
-
|
105
|
+
data = []
|
106
|
+
i = hrp_len + 1
|
107
|
+
while i < input_len
|
108
|
+
ch = input[i].ord
|
109
|
+
v = (ch & 0x80) != 0 ? -1 : CHARSET_REV[ch]
|
127
110
|
|
128
|
-
|
129
|
-
|
111
|
+
have_lower = true if ch >= 'a'.ord && ch <= 'z'.ord
|
112
|
+
have_upper = true if ch >= 'A'.ord && ch <= 'Z'.ord
|
113
|
+
return nil if v == -1
|
130
114
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
# with trailing 0 bits to the nearest byte boundary. Returns nil if
|
135
|
-
# conversion requires padding and pad is false.
|
136
|
-
#
|
137
|
-
# For example:
|
138
|
-
#
|
139
|
-
# convert_bits("\xFF\xFF", from_bits: 8, to_bits: 5, pad: true)
|
140
|
-
# => "\x1F\x1F\x1F\10"
|
141
|
-
#
|
142
|
-
# See https://github.com/bitcoin/bitcoin/blob/595a7bab23bc21049526229054ea1fff1a29c0bf/src/utilstrencodings.h#L154
|
143
|
-
def convert_bits(chunks, from_bits:, to_bits:, pad:)
|
144
|
-
output_mask = (1 << to_bits) - 1
|
145
|
-
buffer_mask = (1 << (from_bits + to_bits - 1)) - 1
|
146
|
-
|
147
|
-
buffer = 0
|
148
|
-
bits = 0
|
149
|
-
|
150
|
-
output = []
|
151
|
-
chunks.each do |chunk|
|
152
|
-
buffer = ((buffer << from_bits) | chunk) & buffer_mask
|
153
|
-
bits += from_bits
|
154
|
-
while bits >= to_bits
|
155
|
-
bits -= to_bits
|
156
|
-
output << ((buffer >> bits) & output_mask)
|
115
|
+
chk = polymod_step(chk) ^ v
|
116
|
+
data << v if (i + 6) < input_len
|
117
|
+
i += 1
|
157
118
|
end
|
158
|
-
end
|
159
119
|
|
160
|
-
|
161
|
-
|
162
|
-
end
|
120
|
+
return nil if have_lower && have_upper
|
121
|
+
return nil if chk != 1
|
163
122
|
|
164
|
-
|
165
|
-
return nil
|
123
|
+
[hrp.pack('C*'), data]
|
166
124
|
end
|
125
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
126
|
+
|
127
|
+
# Utility for converting bytes of data between bases. These is used for
|
128
|
+
# BIP 173 address encoding/decoding to convert between sequences of bytes
|
129
|
+
# representing 8-bit values and groups of 5 bits. Conversions may be padded
|
130
|
+
# with trailing 0 bits to the nearest byte boundary. Returns nil if
|
131
|
+
# conversion requires padding and pad is false.
|
132
|
+
#
|
133
|
+
# For example:
|
134
|
+
#
|
135
|
+
# convert_bits("\xFF\xFF", from_bits: 8, to_bits: 5, pad: true)
|
136
|
+
# => "\x1F\x1F\x1F\10"
|
137
|
+
#
|
138
|
+
# See https://github.com/bitcoin/bitcoin/blob/595a7bab23bc21049526229054ea1fff1a29c0bf/src/utilstrencodings.h#L154
|
139
|
+
def convert_bits(chunks, from_bits:, to_bits:, pad:)
|
140
|
+
output_mask = (1 << to_bits) - 1
|
141
|
+
buffer_mask = (1 << (from_bits + to_bits - 1)) - 1
|
142
|
+
|
143
|
+
buffer = 0
|
144
|
+
bits = 0
|
145
|
+
|
146
|
+
output = []
|
147
|
+
chunks.each do |chunk|
|
148
|
+
buffer = ((buffer << from_bits) | chunk) & buffer_mask
|
149
|
+
bits += from_bits
|
150
|
+
while bits >= to_bits
|
151
|
+
bits -= to_bits
|
152
|
+
output << ((buffer >> bits) & output_mask)
|
153
|
+
end
|
154
|
+
end
|
167
155
|
|
168
|
-
|
169
|
-
end
|
156
|
+
output << ((buffer << (to_bits - bits)) & output_mask) if pad && bits > 0
|
170
157
|
|
158
|
+
if !pad && (bits >= from_bits || ((buffer << (to_bits - bits)) & output_mask) != 0)
|
159
|
+
return nil
|
160
|
+
end
|
161
|
+
|
162
|
+
output
|
163
|
+
end
|
164
|
+
end
|
171
165
|
end
|
172
166
|
end
|
data/lib/bitcoin/bloom_filter.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Bitcoin
|
2
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki
|
2
3
|
class BloomFilter
|
3
4
|
SEED_SHIFT = 0xfba4c795
|
4
|
-
BIT_MASK = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]
|
5
|
+
BIT_MASK = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80].freeze
|
5
6
|
|
6
|
-
MAX_FILTER_SIZE =
|
7
|
+
MAX_FILTER_SIZE = 36_000
|
7
8
|
MAX_HASH_FUNCS = 50
|
8
9
|
|
9
10
|
# flags for filterload message
|
@@ -53,8 +54,8 @@ module Bitcoin
|
|
53
54
|
|
54
55
|
# using #ceil instead of #floor may be better, but it's bitcoinj's way
|
55
56
|
|
56
|
-
calc_m = (-Math.log(fp_rate) * elements / ln2 / ln2 / 8).floor
|
57
|
-
@filter_size = [1, [calc_m, MAX_FILTER_SIZE].min].max
|
57
|
+
calc_m = (-Math.log(fp_rate) * elements / ln2 / ln2 / 8).floor
|
58
|
+
@filter_size = [1, [calc_m, MAX_FILTER_SIZE].min].max
|
58
59
|
@filter = "\x00" * @filter_size
|
59
60
|
|
60
61
|
calc_k = (@filter_size * 8 * ln2 / elements).floor
|
@@ -62,7 +63,7 @@ module Bitcoin
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def rotate_left32(x, r)
|
65
|
-
|
66
|
+
(x << r) | (x >> (32 - r))
|
66
67
|
end
|
67
68
|
|
68
69
|
#
|
@@ -80,13 +81,15 @@ module Bitcoin
|
|
80
81
|
# body
|
81
82
|
while i < num_blocks
|
82
83
|
k1 = (object[i] & 0xFF) |
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
((object[i + 1] & 0xFF) << 8) |
|
85
|
+
((object[i + 2] & 0xFF) << 16) |
|
86
|
+
((object[i + 3] & 0xFF) << 24)
|
86
87
|
|
87
|
-
k1 *= c1
|
88
|
+
k1 *= c1
|
89
|
+
k1 &= 0xffffffff
|
88
90
|
k1 = rotate_left32(k1, 15)
|
89
|
-
k1 *= c2
|
91
|
+
k1 *= c2
|
92
|
+
k1 &= 0xffffffff
|
90
93
|
|
91
94
|
h1 ^= k1
|
92
95
|
h1 = rotate_left32(h1, 13)
|
@@ -97,29 +100,29 @@ module Bitcoin
|
|
97
100
|
|
98
101
|
k1 = 0
|
99
102
|
flg = object.length & 3
|
100
|
-
if flg >= 3
|
101
|
-
|
102
|
-
end
|
103
|
-
if flg >= 2
|
104
|
-
k1 ^= (object[num_blocks + 1] & 0xff) << 8
|
105
|
-
end
|
103
|
+
k1 ^= (object[num_blocks + 2] & 0xff) << 16 if flg >= 3
|
104
|
+
k1 ^= (object[num_blocks + 1] & 0xff) << 8 if flg >= 2
|
106
105
|
if flg >= 1
|
107
106
|
k1 ^= (object[num_blocks] & 0xff)
|
108
|
-
k1 *= c1
|
107
|
+
k1 *= c1
|
108
|
+
k1 &= 0xffffffff
|
109
109
|
k1 = rotate_left32(k1, 15)
|
110
|
-
k1 *= c2
|
110
|
+
k1 *= c2
|
111
|
+
k1 &= 0xffffffff
|
111
112
|
h1 ^= k1
|
112
113
|
end
|
113
114
|
|
114
115
|
# finalization
|
115
116
|
h1 ^= object.length
|
116
117
|
h1 ^= h1 >> 16
|
117
|
-
h1 *= 0x85ebca6b
|
118
|
+
h1 *= 0x85ebca6b
|
119
|
+
h1 &= 0xffffffff
|
118
120
|
h1 ^= h1 >> 13
|
119
|
-
h1 *= 0xc2b2ae35
|
121
|
+
h1 *= 0xc2b2ae35
|
122
|
+
h1 &= 0xffffffff
|
120
123
|
h1 ^= h1 >> 16
|
121
124
|
|
122
|
-
|
125
|
+
(h1 & 0xffffffff) % (@filter_size * 8)
|
123
126
|
end
|
124
127
|
end
|
125
128
|
end
|
data/lib/bitcoin/builder.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
3
|
module Bitcoin
|
4
|
-
|
5
4
|
# Optional DSL to help create blocks and transactions.
|
6
5
|
#
|
7
6
|
# see also BlockBuilder, TxBuilder, TxInBuilder, TxOutBuilder, ScriptBuilder
|
8
7
|
module Builder
|
9
|
-
|
10
8
|
# build a Bitcoin::Protocol::Block matching the given +target+.
|
11
9
|
# see BlockBuilder for details.
|
12
|
-
def build_block(target =
|
10
|
+
def build_block(target = '00'.ljust(64, 'f'))
|
13
11
|
c = BlockBuilder.new
|
14
12
|
yield c
|
15
13
|
c.block(target)
|
@@ -17,7 +15,7 @@ module Bitcoin
|
|
17
15
|
|
18
16
|
# build a Bitcoin::Protocol::Tx.
|
19
17
|
# see TxBuilder for details.
|
20
|
-
def build_tx
|
18
|
+
def build_tx(opts = {})
|
21
19
|
c = TxBuilder.new
|
22
20
|
yield c
|
23
21
|
c.tx opts
|
@@ -45,35 +43,44 @@ module Bitcoin
|
|
45
43
|
#
|
46
44
|
# See Bitcoin::Builder::TxBuilder for details on building transactions.
|
47
45
|
class BlockBuilder
|
46
|
+
attr_writer :prev_block, :time, :version
|
48
47
|
|
49
48
|
def initialize
|
50
49
|
@block = P::Block.new(nil)
|
51
50
|
end
|
52
51
|
|
53
52
|
# specify block version. this is usually not necessary. defaults to 1.
|
54
|
-
def version
|
53
|
+
def version(v) # rubocop:disable Style/TrivialAccessors
|
55
54
|
@version = v
|
56
55
|
end
|
57
56
|
|
58
57
|
# set the hash of the previous block.
|
59
|
-
def prev_block
|
58
|
+
def prev_block(hash) # rubocop:disable Style/TrivialAccessors
|
60
59
|
@prev_block = hash
|
61
60
|
end
|
62
61
|
|
63
62
|
# set the block timestamp (defaults to current time).
|
64
|
-
def time
|
63
|
+
def time(time) # rubocop:disable Style/TrivialAccessors
|
65
64
|
@time = time
|
66
65
|
end
|
67
66
|
|
68
67
|
# add transactions to the block (see TxBuilder).
|
69
|
-
def tx
|
70
|
-
tx ||=
|
68
|
+
def tx(tx = nil)
|
69
|
+
tx ||= begin
|
70
|
+
c = TxBuilder.new
|
71
|
+
yield c
|
72
|
+
c.tx
|
73
|
+
end
|
71
74
|
@block.tx << tx
|
72
75
|
tx
|
73
76
|
end
|
74
77
|
|
75
78
|
# create the block according to values specified via DSL.
|
76
|
-
def block
|
79
|
+
def block(target)
|
80
|
+
@version ||= nil
|
81
|
+
@mrkl_root ||= nil
|
82
|
+
@time ||= nil
|
83
|
+
|
77
84
|
@block.ver = @version || 1
|
78
85
|
@block.prev_block = @prev_block.htb.reverse
|
79
86
|
@block.mrkl_root = @mrkl_root
|
@@ -82,33 +89,31 @@ module Bitcoin
|
|
82
89
|
@block.mrkl_root = Bitcoin.hash_mrkl_tree(@block.tx.map(&:hash)).last.htb.reverse
|
83
90
|
find_hash(target)
|
84
91
|
block = P::Block.new(@block.to_payload)
|
85
|
-
raise
|
92
|
+
raise 'Payload Error' unless block.to_payload == @block.to_payload
|
86
93
|
block
|
87
94
|
end
|
88
95
|
|
89
96
|
private
|
90
97
|
|
91
98
|
# increment nonce/time to find a block hash matching the +target+.
|
92
|
-
def find_hash
|
99
|
+
def find_hash(target)
|
93
100
|
@block.bits = Bitcoin.encode_compact_bits(target)
|
94
101
|
t = Time.now
|
95
102
|
@block.recalc_block_hash
|
96
103
|
until @block.hash.to_i(16) < target.to_i(16)
|
97
104
|
@block.nonce += 1
|
98
105
|
@block.recalc_block_hash
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
t = Time.now
|
105
|
-
@block.time = Time.now.to_i
|
106
|
-
@block.nonce = 0
|
107
|
-
$stdout.flush
|
106
|
+
next unless @block.nonce == 100_000
|
107
|
+
if t
|
108
|
+
tt = 1 / ((Time.now - t) / 100_000) / 1000
|
109
|
+
print format("\r%.2f khash/s", tt)
|
108
110
|
end
|
111
|
+
t = Time.now
|
112
|
+
@block.time = Time.now.to_i
|
113
|
+
@block.nonce = 0
|
114
|
+
$stdout.flush
|
109
115
|
end
|
110
116
|
end
|
111
|
-
|
112
117
|
end
|
113
118
|
|
114
119
|
# DSL to create Bitcoin::Protocol::Tx used by Builder#build_tx.
|
@@ -129,20 +134,21 @@ module Bitcoin
|
|
129
134
|
#
|
130
135
|
# See TxInBuilder and TxOutBuilder for details on how to build in/outputs.
|
131
136
|
class TxBuilder
|
132
|
-
|
133
137
|
def initialize
|
134
138
|
@tx = P::Tx.new(nil)
|
135
|
-
@tx.ver
|
136
|
-
@
|
139
|
+
@tx.ver = 1
|
140
|
+
@tx.lock_time = 0
|
141
|
+
@ins = []
|
142
|
+
@outs = []
|
137
143
|
end
|
138
144
|
|
139
145
|
# specify tx version. this is usually not necessary. defaults to 1.
|
140
|
-
def version
|
146
|
+
def version(n)
|
141
147
|
@tx.ver = n
|
142
148
|
end
|
143
149
|
|
144
150
|
# specify tx lock_time. this is usually not necessary. defaults to 0.
|
145
|
-
def lock_time
|
151
|
+
def lock_time(n)
|
146
152
|
@tx.lock_time = n
|
147
153
|
end
|
148
154
|
|
@@ -154,10 +160,10 @@ module Bitcoin
|
|
154
160
|
end
|
155
161
|
|
156
162
|
# add an output to the transaction (see TxOutBuilder).
|
157
|
-
def output
|
163
|
+
def output(value = nil, recipient = nil, type = :address)
|
158
164
|
c = TxOutBuilder.new
|
159
165
|
c.value(value) if value
|
160
|
-
c.to(recipient, type)
|
166
|
+
c.to(recipient, type) if recipient
|
161
167
|
yield c if block_given?
|
162
168
|
@outs << c
|
163
169
|
end
|
@@ -172,14 +178,15 @@ module Bitcoin
|
|
172
178
|
# to the given address. The :leave_fee option can be used in this
|
173
179
|
# case to specify a tx fee that should be left unclaimed by the
|
174
180
|
# change output.
|
175
|
-
|
181
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
182
|
+
def tx(opts = {})
|
176
183
|
return @tx if @tx.hash
|
177
184
|
|
178
185
|
if opts[:change_address] && !opts[:input_value]
|
179
186
|
raise "Must give 'input_value' when auto-generating change output!"
|
180
187
|
end
|
181
|
-
@ins.each {|i| @tx.add_in(i.txin) }
|
182
|
-
@outs.each {|o| @tx.add_out(o.txout) }
|
188
|
+
@ins.each { |i| @tx.add_in(i.txin) }
|
189
|
+
@outs.each { |o| @tx.add_out(o.txout) }
|
183
190
|
if opts[:change_address]
|
184
191
|
output_value = @tx.out.map(&:value).inject(:+) || 0
|
185
192
|
change_value = opts[:input_value] - output_value
|
@@ -202,7 +209,7 @@ module Bitcoin
|
|
202
209
|
end
|
203
210
|
|
204
211
|
# run our tx through an encode/decode cycle to make sure that the binary format is sane
|
205
|
-
raise
|
212
|
+
raise 'Payload Error' unless P::Tx.new(@tx.to_witness_payload).to_payload == @tx.to_payload
|
206
213
|
@tx.instance_eval do
|
207
214
|
@payload = to_payload
|
208
215
|
@hash = hash_from_payload(@payload)
|
@@ -210,38 +217,44 @@ module Bitcoin
|
|
210
217
|
|
211
218
|
@tx
|
212
219
|
end
|
220
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
213
221
|
|
214
222
|
# coinbase inputs don't need to be signed, they only include the given +coinbase_data+
|
215
|
-
def include_coinbase_data
|
216
|
-
script_sig = [inc.coinbase_data].pack(
|
223
|
+
def include_coinbase_data(i, inc)
|
224
|
+
script_sig = [inc.coinbase_data].pack('H*')
|
217
225
|
@tx.in[i].script_sig_length = script_sig.bytesize
|
218
226
|
@tx.in[i].script_sig = script_sig
|
219
227
|
end
|
220
228
|
|
221
229
|
def sig_hash_and_all_keys_exist?(inc, sig_script)
|
222
|
-
return false unless @sig_hash && inc.
|
230
|
+
return false unless @sig_hash && inc.keys?
|
223
231
|
script = Bitcoin::Script.new(sig_script)
|
224
|
-
return true if script.is_hash160? ||
|
232
|
+
return true if script.is_hash160? ||
|
233
|
+
script.is_pubkey? ||
|
234
|
+
script.is_witness_v0_keyhash? ||
|
235
|
+
(Bitcoin.namecoin? && script.is_namecoin?)
|
225
236
|
if script.is_multisig?
|
226
|
-
return inc.
|
237
|
+
return inc.multiple_keys? && inc.key.size >= script.get_signatures_required
|
227
238
|
end
|
228
|
-
raise
|
239
|
+
raise 'Script type must be hash160, pubkey, p2wpkh or multisig'
|
229
240
|
end
|
230
241
|
|
231
242
|
def add_empty_script_sig_to_input(i)
|
232
243
|
@tx.in[i].script_sig_length = 0
|
233
|
-
@tx.in[i].script_sig =
|
244
|
+
@tx.in[i].script_sig = ''
|
234
245
|
# add the sig_hash that needs to be signed, so it can be passed on to a signing device
|
235
246
|
@tx.in[i].sig_hash = @sig_hash
|
236
|
-
# add the address the sig_hash needs to be signed with as a convenience for the
|
237
|
-
|
247
|
+
# add the address the sig_hash needs to be signed with as a convenience for the
|
248
|
+
# signing device
|
249
|
+
@tx.in[i].sig_address = Script.new(@prev_script).get_address if @prev_script
|
238
250
|
end
|
239
251
|
|
240
252
|
def get_script_sig(inc, hash_type)
|
241
|
-
if inc.
|
253
|
+
if inc.multiple_keys?
|
242
254
|
# multiple keys given, generate signature for each one
|
243
255
|
sigs = inc.sign(@sig_hash)
|
244
|
-
|
256
|
+
redeem_script = inc.instance_eval { @redeem_script }
|
257
|
+
if redeem_script
|
245
258
|
# when a redeem_script was specified, assume we spend a p2sh multisig script
|
246
259
|
script_sig = Script.to_p2sh_multisig_script_sig(redeem_script, sigs)
|
247
260
|
else
|
@@ -251,73 +264,80 @@ module Bitcoin
|
|
251
264
|
else
|
252
265
|
# only one key given, generate signature and script_sig
|
253
266
|
sig = inc.sign(@sig_hash)
|
254
|
-
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack(
|
267
|
+
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack('H*'), hash_type)
|
255
268
|
end
|
256
|
-
|
269
|
+
script_sig
|
257
270
|
end
|
258
271
|
|
259
272
|
# Sign input number +i+ with data from given +inc+ object (a TxInBuilder).
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
273
|
+
# rubocop:disable CyclomaticComplexity,PerceivedComplexity
|
274
|
+
def sign_input(i, inc)
|
275
|
+
return include_coinbase_data(i, inc) if @tx.in[i].coinbase?
|
276
|
+
@prev_script = inc.instance_variable_get(:@prev_out_script)
|
277
|
+
|
278
|
+
# get the signature script; use +redeem_script+ if given
|
279
|
+
# (indicates spending a p2sh output), otherwise use the prev_script
|
280
|
+
sig_script = inc.instance_eval { @redeem_script }
|
281
|
+
sig_script ||= @prev_script
|
282
|
+
|
283
|
+
hash_type = if inc.prev_out_forkid
|
284
|
+
Script::SIGHASH_TYPE[:all] | Script::SIGHASH_TYPE[:forkid]
|
285
|
+
else
|
286
|
+
Script::SIGHASH_TYPE[:all]
|
287
|
+
end
|
288
|
+
|
289
|
+
# when a sig_script was found, generate the sig_hash to be signed
|
290
|
+
if sig_script
|
291
|
+
script = Script.new(sig_script)
|
292
|
+
@sig_hash = if script.is_witness_v0_keyhash?
|
293
|
+
@tx.signature_hash_for_witness_input(i, sig_script, inc.value)
|
294
|
+
elsif inc.prev_out_forkid
|
295
|
+
@tx.signature_hash_for_input(
|
296
|
+
i,
|
297
|
+
sig_script,
|
298
|
+
hash_type,
|
299
|
+
inc.value,
|
300
|
+
inc.prev_out_forkid
|
301
|
+
)
|
302
|
+
else
|
303
|
+
@tx.signature_hash_for_input(i, sig_script)
|
304
|
+
end
|
305
|
+
end
|
265
306
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
307
|
+
# when there is a sig_hash and one or more signature_keys were specified
|
308
|
+
if sig_hash_and_all_keys_exist?(inc, sig_script)
|
309
|
+
# add the script_sig to the txin
|
310
|
+
if script.is_witness_v0_keyhash? # for p2wpkh
|
311
|
+
@tx.in[i].script_witness.stack << inc.sign(@sig_hash) + \
|
312
|
+
[Script::SIGHASH_TYPE[:all]].pack('C')
|
313
|
+
@tx.in[i].script_witness.stack << inc.key.pub.htb
|
270
314
|
|
271
|
-
|
272
|
-
|
315
|
+
redeem_script = inc.instance_eval { @redeem_script }
|
316
|
+
@tx.in[i].script_sig = Bitcoin::Script.pack_pushdata(redeem_script) if redeem_script
|
273
317
|
else
|
274
|
-
|
318
|
+
@tx.in[i].script_sig = get_script_sig(inc, hash_type)
|
275
319
|
end
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
@tx.signature_hash_for_input(
|
285
|
-
i,
|
286
|
-
sig_script,
|
287
|
-
hash_type,
|
288
|
-
inc.value,
|
289
|
-
inc.prev_out_forkid)
|
290
|
-
else
|
291
|
-
@tx.signature_hash_for_input(i, sig_script)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
# when there is a sig_hash and one or more signature_keys were specified
|
297
|
-
if sig_hash_and_all_keys_exist?(inc, sig_script)
|
298
|
-
# add the script_sig to the txin
|
299
|
-
if script.is_witness_v0_keyhash? # for p2wpkh
|
300
|
-
@tx.in[i].script_witness.stack << inc.sign(@sig_hash) + [Script::SIGHASH_TYPE[:all]].pack("C")
|
301
|
-
@tx.in[i].script_witness.stack << inc.key.pub.htb
|
302
|
-
else
|
303
|
-
@tx.in[i].script_sig = get_script_sig(inc, hash_type)
|
304
|
-
end
|
305
|
-
# double-check that the script_sig is valid to spend the given prev_script
|
306
|
-
if @prev_script && !inc.prev_out_forkid && !@tx.verify_input_signature(i, @prev_script)
|
307
|
-
raise "Signature error"
|
308
|
-
end
|
309
|
-
elsif inc.has_multiple_keys?
|
310
|
-
raise "Keys missing for multisig signing"
|
311
|
-
else
|
312
|
-
# no sig_hash, add an empty script_sig.
|
313
|
-
add_empty_script_sig_to_input(i)
|
320
|
+
# double-check that the script_sig is valid to spend the given prev_script
|
321
|
+
if @prev_script && !inc.prev_out_forkid
|
322
|
+
verified = if script.is_witness_v0_keyhash?
|
323
|
+
@tx.verify_witness_input_signature(i, @prev_script, inc.value)
|
324
|
+
else
|
325
|
+
@tx.verify_input_signature(i, @prev_script)
|
326
|
+
end
|
327
|
+
raise 'Signature error' unless verified
|
314
328
|
end
|
329
|
+
elsif inc.multiple_keys?
|
330
|
+
raise 'Keys missing for multisig signing'
|
331
|
+
else
|
332
|
+
# no sig_hash, add an empty script_sig.
|
333
|
+
add_empty_script_sig_to_input(i)
|
315
334
|
end
|
316
335
|
end
|
336
|
+
# rubocop:enable CyclomaticComplexity,PerceivedComplexity
|
317
337
|
|
318
338
|
# Randomize the outputs using SecureRandom
|
319
339
|
def randomize_outputs
|
320
|
-
@outs.sort_by!{ SecureRandom.random_bytes(4).unpack(
|
340
|
+
@outs.sort_by! { SecureRandom.random_bytes(4).unpack('I')[0] }
|
321
341
|
end
|
322
342
|
end
|
323
343
|
|
@@ -346,45 +366,48 @@ module Bitcoin
|
|
346
366
|
#
|
347
367
|
# If you want to spend a multisig output, just provide an array of keys to #signature_key.
|
348
368
|
class TxInBuilder
|
349
|
-
attr_reader :
|
369
|
+
attr_reader :coinbase_data, :key, :prev_out_forkid, :prev_script, :prev_tx
|
370
|
+
attr_writer :prev_out_script, :prev_out_value, :redeem_script, :sequence
|
350
371
|
|
351
372
|
def initialize
|
352
373
|
@txin = P::TxIn.new
|
353
374
|
@prev_out_hash = "\x00" * 32
|
354
375
|
@prev_out_index = 0
|
376
|
+
@redeem_script = nil
|
377
|
+
@key = nil
|
355
378
|
end
|
356
379
|
|
357
380
|
# Previous transaction that contains the output we want to use.
|
358
381
|
# You can either pass the transaction, or just the tx hash.
|
359
382
|
# If you pass only the hash, you need to pass the previous outputs
|
360
383
|
# +script+ separately if you want the txin to be signed.
|
361
|
-
def prev_out
|
384
|
+
def prev_out(tx, idx = nil, script = nil, prev_value = nil, prev_forkid = nil)
|
362
385
|
@prev_out_forkid = prev_forkid
|
363
386
|
if tx.is_a?(Bitcoin::P::Tx)
|
364
387
|
@prev_tx = tx
|
365
388
|
@prev_out_hash = tx.binary_hash
|
366
|
-
@prev_out_script = tx.out[idx].pk_script
|
389
|
+
@prev_out_script = tx.out[idx].pk_script if idx
|
367
390
|
else
|
368
391
|
@prev_out_hash = tx.htb.reverse
|
369
392
|
end
|
370
|
-
@prev_out_script = script
|
371
|
-
@prev_out_index = idx
|
393
|
+
@prev_out_script = script if script
|
394
|
+
@prev_out_index = idx if idx
|
372
395
|
@prev_out_value = prev_value if prev_value
|
373
396
|
end
|
374
397
|
|
375
398
|
# Index of the output in the #prev_out transaction.
|
376
|
-
def prev_out_index
|
399
|
+
def prev_out_index(i)
|
377
400
|
@prev_out_index = i
|
378
|
-
@prev_out_script = @prev_tx.out[i].pk_script
|
401
|
+
@prev_out_script = @prev_tx.out[i].pk_script if @prev_tx
|
379
402
|
end
|
380
403
|
|
381
404
|
# Previous output's +pk_script+. Needed when only the tx hash is specified as #prev_out.
|
382
|
-
def prev_out_script
|
405
|
+
def prev_out_script(script) # rubocop:disable Style/TrivialAccessors
|
383
406
|
@prev_out_script = script
|
384
407
|
end
|
385
408
|
|
386
409
|
# Previous output's +value+. Needed when only spend segwit utxo.
|
387
|
-
def prev_out_value
|
410
|
+
def prev_out_value(value) # rubocop:disable Style/TrivialAccessors
|
388
411
|
@prev_out_value = value
|
389
412
|
end
|
390
413
|
|
@@ -394,52 +417,70 @@ module Bitcoin
|
|
394
417
|
|
395
418
|
# Redeem script for P2SH output. To spend from a P2SH output, you need to provide
|
396
419
|
# the script with a hash matching the P2SH address.
|
397
|
-
def redeem_script
|
420
|
+
def redeem_script(script) # rubocop:disable Style/TrivialAccessors
|
398
421
|
@redeem_script = script
|
399
422
|
end
|
400
423
|
|
401
424
|
# Specify sequence. This is usually not needed.
|
402
|
-
def sequence
|
425
|
+
def sequence(s) # rubocop:disable Style/TrivialAccessors
|
403
426
|
@sequence = s
|
404
427
|
end
|
405
428
|
|
406
429
|
# Bitcoin::Key used to sign the signature_hash for the input.
|
407
430
|
# see Bitcoin::Script.signature_hash_for_input and Bitcoin::Key.sign.
|
408
|
-
def signature_key
|
431
|
+
def signature_key(key)
|
409
432
|
@key = key
|
410
433
|
end
|
411
434
|
|
412
435
|
# Specify that this is a coinbase input. Optionally set +data+.
|
413
436
|
# If this is set, no other options need to be given.
|
414
|
-
def coinbase
|
437
|
+
def coinbase(data = nil)
|
415
438
|
@coinbase_data = data || OpenSSL::Random.random_bytes(32)
|
416
439
|
@prev_out_hash = "\x00" * 32
|
417
|
-
@prev_out_index =
|
440
|
+
@prev_out_index = 4_294_967_295
|
418
441
|
end
|
419
442
|
|
420
443
|
# Create the txin according to specified values
|
421
444
|
def txin
|
445
|
+
@sequence ||= nil
|
422
446
|
@txin.prev_out = @prev_out_hash
|
423
447
|
@txin.prev_out_index = @prev_out_index
|
424
448
|
@txin.sequence = @sequence || "\xff\xff\xff\xff"
|
425
449
|
@txin
|
426
450
|
end
|
427
451
|
|
428
|
-
def
|
452
|
+
def multiple_keys?
|
429
453
|
@key.is_a?(Array)
|
430
454
|
end
|
431
455
|
|
432
|
-
def
|
433
|
-
|
456
|
+
def has_multiple_keys? # rubocop:disable Naming/PredicateName
|
457
|
+
warn '[DEPRECATION] `TxInBuilder.has_multiple_keys?` is deprecated. ' \
|
458
|
+
'Use `multiple_keys?` instaed.'
|
459
|
+
multiple_keys?
|
460
|
+
end
|
461
|
+
|
462
|
+
def keys?
|
463
|
+
@key && (multiple_keys? ? @key.all?(&:priv) : @key.priv)
|
434
464
|
end
|
435
465
|
|
436
|
-
def
|
466
|
+
def has_keys? # rubocop:disable Naming/PredicateName
|
467
|
+
warn '[DEPRECATION] `TxInBuilder.has_keys?` is deprecated. Use `keys?` instead.'
|
468
|
+
keys?
|
469
|
+
end
|
470
|
+
|
471
|
+
def witness_v0_keyhash?
|
437
472
|
@prev_out_script && Script.new(@prev_out_script).is_witness_v0_keyhash?
|
438
473
|
end
|
439
474
|
|
475
|
+
def is_witness_v0_keyhash? # rubocop:disable Naming/PredicateName
|
476
|
+
warn '[DEPRECATION] `TxInBuilder.is_witness_v0_keyhash?` is deprecated. ' \
|
477
|
+
'Use `witness_v0_keyhash?` instead.'
|
478
|
+
witness_v0_keyhash?
|
479
|
+
end
|
480
|
+
|
440
481
|
def sign(sig_hash)
|
441
|
-
if
|
442
|
-
@key.map {|k| k.sign(sig_hash) }
|
482
|
+
if multiple_keys?
|
483
|
+
@key.map { |k| k.sign(sig_hash) }
|
443
484
|
else
|
444
485
|
@key.sign(sig_hash)
|
445
486
|
end
|
@@ -457,14 +498,14 @@ module Bitcoin
|
|
457
498
|
|
458
499
|
# Script type (:pubkey, :address/hash160, :multisig).
|
459
500
|
# Defaults to :address.
|
460
|
-
def type
|
501
|
+
def type(type)
|
461
502
|
@type = type.to_sym
|
462
503
|
end
|
463
504
|
|
464
505
|
# Recipient(s) of the script.
|
465
506
|
# Depending on the #type, this should be an address, a hash160 pubkey,
|
466
507
|
# or an array of multisig pubkeys.
|
467
|
-
def recipient
|
508
|
+
def recipient(*data)
|
468
509
|
@script, @redeem_script = *Script.send("to_#{@type}_script", *data)
|
469
510
|
end
|
470
511
|
end
|
@@ -490,23 +531,24 @@ module Bitcoin
|
|
490
531
|
end
|
491
532
|
|
492
533
|
# Set output value (in base units / "satoshis")
|
493
|
-
def value
|
534
|
+
def value(value)
|
494
535
|
@txout.value = value
|
495
536
|
end
|
496
537
|
|
497
538
|
# Set recipient address and script type (defaults to :address).
|
498
|
-
def to
|
499
|
-
@txout.pk_script, @txout.redeem_script = *Bitcoin::Script.send(
|
539
|
+
def to(recipient, type = :address)
|
540
|
+
@txout.pk_script, @txout.redeem_script = *Bitcoin::Script.send(
|
541
|
+
"to_#{type}_script", *recipient
|
542
|
+
)
|
500
543
|
end
|
501
544
|
|
502
545
|
# Add a script to the output (see ScriptBuilder).
|
503
|
-
def script
|
546
|
+
def script
|
504
547
|
c = ScriptBuilder.new
|
505
548
|
yield c
|
506
|
-
@txout.pk_script
|
549
|
+
@txout.pk_script = c.script
|
550
|
+
@txout.redeem_script = c.redeem_script
|
507
551
|
end
|
508
|
-
|
509
552
|
end
|
510
|
-
|
511
553
|
end
|
512
554
|
end
|