bitcoin-ruby 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +2 -2
- data/COPYING +1 -1
- data/Gemfile +5 -11
- data/README.rdoc +11 -5
- data/Rakefile +5 -0
- data/bin/bitcoin_node +11 -29
- data/bin/bitcoin_node_cli +81 -0
- data/bin/bitcoin_wallet +9 -6
- data/doc/NODE.rdoc +79 -26
- data/examples/bbe_verify_tx.rb +1 -1
- data/examples/index_nhash.rb +24 -0
- data/examples/reindex_p2sh_addrs.rb +44 -0
- data/lib/bitcoin.rb +135 -20
- data/lib/bitcoin/builder.rb +233 -63
- data/lib/bitcoin/key.rb +89 -16
- data/lib/bitcoin/litecoin.rb +13 -11
- data/lib/bitcoin/namecoin.rb +5 -4
- data/lib/bitcoin/network/command_client.rb +23 -13
- data/lib/bitcoin/network/command_handler.rb +336 -131
- data/lib/bitcoin/network/connection_handler.rb +14 -13
- data/lib/bitcoin/network/node.rb +61 -20
- data/lib/bitcoin/protocol.rb +5 -1
- data/lib/bitcoin/protocol/block.rb +15 -3
- data/lib/bitcoin/protocol/parser.rb +3 -3
- data/lib/bitcoin/protocol/tx.rb +82 -20
- data/lib/bitcoin/protocol/txin.rb +7 -0
- data/lib/bitcoin/protocol/txout.rb +12 -9
- data/lib/bitcoin/script.rb +329 -75
- data/lib/bitcoin/storage/dummy/dummy_store.rb +23 -4
- data/lib/bitcoin/storage/models.rb +6 -11
- data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +14 -0
- data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +31 -0
- data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +16 -0
- data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +31 -0
- data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +56 -0
- data/lib/bitcoin/storage/sequel/sequel_store.rb +168 -70
- data/lib/bitcoin/storage/storage.rb +161 -97
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +1 -1
- data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +14 -0
- data/lib/bitcoin/storage/utxo/utxo_store.rb +25 -12
- data/lib/bitcoin/validation.rb +87 -56
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bitcoin_spec.rb +38 -0
- data/spec/bitcoin/builder_spec.rb +177 -0
- data/spec/bitcoin/fixtures/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +259 -0
- data/spec/bitcoin/fixtures/rawblock-testnet-265322.bin +0 -0
- data/spec/bitcoin/fixtures/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +64 -0
- data/spec/bitcoin/fixtures/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +64 -0
- data/spec/bitcoin/fixtures/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +64 -0
- data/spec/bitcoin/fixtures/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +64 -0
- data/spec/bitcoin/fixtures/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +28 -0
- data/spec/bitcoin/fixtures/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +23 -0
- data/spec/bitcoin/fixtures/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +64 -0
- data/spec/bitcoin/fixtures/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +64 -0
- data/spec/bitcoin/fixtures/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +64 -0
- data/spec/bitcoin/fixtures/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +64 -0
- data/spec/bitcoin/fixtures/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +64 -0
- data/spec/bitcoin/fixtures/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +28 -0
- data/spec/bitcoin/fixtures/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +30 -0
- data/spec/bitcoin/fixtures/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +23 -0
- data/spec/bitcoin/fixtures/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +64 -0
- data/spec/bitcoin/fixtures/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +32 -0
- data/spec/bitcoin/fixtures/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +64 -0
- data/spec/bitcoin/fixtures/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +38 -0
- data/spec/bitcoin/fixtures/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +23 -0
- data/spec/bitcoin/fixtures/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +30 -0
- data/spec/bitcoin/fixtures/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +64 -0
- data/spec/bitcoin/fixtures/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +23 -0
- data/spec/bitcoin/fixtures/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +27 -0
- data/spec/bitcoin/fixtures/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +28 -0
- data/spec/bitcoin/fixtures/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +64 -0
- data/spec/bitcoin/fixtures/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +40 -0
- data/spec/bitcoin/fixtures/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +64 -0
- data/spec/bitcoin/fixtures/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +64 -0
- data/spec/bitcoin/fixtures/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +64 -0
- data/spec/bitcoin/fixtures/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +64 -0
- data/spec/bitcoin/fixtures/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +23 -0
- data/spec/bitcoin/fixtures/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +23 -0
- data/spec/bitcoin/fixtures/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +27 -0
- data/spec/bitcoin/fixtures/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +64 -0
- data/spec/bitcoin/fixtures/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +27 -0
- data/spec/bitcoin/fixtures/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +28 -0
- data/spec/bitcoin/fixtures/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +36 -0
- data/spec/bitcoin/fixtures/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +23 -0
- data/spec/bitcoin/fixtures/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +28 -0
- data/spec/bitcoin/fixtures/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +406 -0
- data/spec/bitcoin/fixtures/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +35 -0
- data/spec/bitcoin/fixtures/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +64 -0
- data/spec/bitcoin/fixtures/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +1 -0
- data/spec/bitcoin/helpers/fake_blockchain.rb +183 -0
- data/spec/bitcoin/key_spec.rb +79 -8
- data/spec/bitcoin/namecoin_spec.rb +1 -1
- data/spec/bitcoin/node/command_api_spec.rb +373 -86
- data/spec/bitcoin/performance/storage_spec.rb +41 -0
- data/spec/bitcoin/protocol/addr_spec.rb +7 -5
- data/spec/bitcoin/protocol/aux_pow_spec.rb +1 -0
- data/spec/bitcoin/protocol/block_spec.rb +6 -0
- data/spec/bitcoin/protocol/tx_spec.rb +184 -1
- data/spec/bitcoin/protocol/txin_spec.rb +27 -0
- data/spec/bitcoin/protocol/txout_spec.rb +27 -0
- data/spec/bitcoin/script/opcodes_spec.rb +74 -3
- data/spec/bitcoin/script/script_spec.rb +271 -0
- data/spec/bitcoin/spec_helper.rb +34 -6
- data/spec/bitcoin/storage/models_spec.rb +104 -0
- data/spec/bitcoin/storage/reorg_spec.rb +42 -11
- data/spec/bitcoin/storage/storage_spec.rb +58 -15
- data/spec/bitcoin/storage/validation_spec.rb +44 -14
- data/spec/bitcoin/wallet/keygenerator_spec.rb +6 -3
- data/spec/bitcoin/wallet/keystore_spec.rb +3 -3
- data/spec/bitcoin/wallet/wallet_spec.rb +87 -89
- metadata +117 -11
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
require_relative '../helpers/fake_blockchain'
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
[
|
8
|
+
[:sequel, :postgres]
|
9
|
+
].compact.each do |options|
|
10
|
+
|
11
|
+
next unless storage = setup_db(*options)
|
12
|
+
|
13
|
+
describe "#{storage.backend_name} block storage" do
|
14
|
+
|
15
|
+
before do
|
16
|
+
@store = storage
|
17
|
+
@store.reset
|
18
|
+
@store.log.level = :error
|
19
|
+
@fake_chain = FakeBlockchain.new 10
|
20
|
+
end
|
21
|
+
|
22
|
+
it "block storage" do
|
23
|
+
blocks = (0..10).to_a.map{|i| @fake_chain.block(i) }
|
24
|
+
|
25
|
+
bm = Benchmark.measure do
|
26
|
+
bm = Benchmark.bm do |b|
|
27
|
+
blocks.each.with_index do |blk,i|
|
28
|
+
b.report("storing fake block ##{i}") do
|
29
|
+
depth, chain = @store.new_block blk
|
30
|
+
chain.should == 0
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
puts '-'*80
|
36
|
+
puts "TOTAL #{bm.format}"
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -40,11 +40,13 @@ describe 'Bitcoin::Protocol::Addr' do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'initalize time, service and port' do
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
Time.freeze do
|
44
|
+
addr = Bitcoin::Protocol::Addr.new(nil)
|
45
|
+
addr[:time].should == Time.now.to_i
|
46
|
+
addr[:service] .should == 1
|
47
|
+
addr[:port] .should == Bitcoin.network[:default_port]
|
48
|
+
addr[:ip] .should == "127.0.0.1"
|
49
|
+
end
|
48
50
|
end
|
49
51
|
|
50
52
|
it 'addr payload' do
|
@@ -19,6 +19,7 @@ describe 'Bitcoin::Protocol::Block' do
|
|
19
19
|
'131025' => fixtures_file('rawblock-131025.bin'),
|
20
20
|
# block 26478: 000000000214a3f06ee99a033a7f2252762d6a18d27c3cd8c8fe2278190da9f3
|
21
21
|
'testnet-26478' => fixtures_file('rawblock-testnet-26478.bin'),
|
22
|
+
'testnet-265322' => fixtures_file('rawblock-testnet-265322.bin'),
|
22
23
|
}
|
23
24
|
end
|
24
25
|
|
@@ -193,4 +194,9 @@ describe 'Bitcoin::Protocol::Block' do
|
|
193
194
|
block.bip34_block_height.should == 197657
|
194
195
|
end
|
195
196
|
|
197
|
+
it 'should work with huge block version' do
|
198
|
+
Bitcoin::P::Block.new(@blocks['testnet-265322']).hash.should ==
|
199
|
+
"0000000000014b351588a177be099e39afd4962cd3d58e9ab5cbe45a9cf83c8a"
|
200
|
+
end
|
201
|
+
|
196
202
|
end
|
@@ -49,6 +49,23 @@ describe 'Tx' do
|
|
49
49
|
tx.binary_hash.should == "\xB4\x02-\x9F\xE5(\xFB\x90pP\x01\x16K\f\xC3\xA8\xF5\xA1\x9C\xB8\xED\x02\xBF\xD4\xFC,\xB6%f\xD1\x9Dn"
|
50
50
|
end
|
51
51
|
|
52
|
+
it '#normalized_hash' do
|
53
|
+
tx = Tx.new( @payload[0] )
|
54
|
+
tx.normalized_hash.size.should == 64
|
55
|
+
tx.normalized_hash.should == "402e30100b6937cc13828ca096377c93afc0ff227ad2f249245e5b1db9123a39"
|
56
|
+
|
57
|
+
new_tx = JSON.parse(tx.to_json)
|
58
|
+
script = Bitcoin::Script.from_string(new_tx['in'][0]['scriptSig'])
|
59
|
+
script.chunks[0].bitcoin_pushdata = Bitcoin::Script::OP_PUSHDATA2
|
60
|
+
script.chunks[0].bitcoin_pushdata_length = script.chunks[0].bytesize
|
61
|
+
new_tx['in'][0]['scriptSig'] = script.to_string
|
62
|
+
new_tx = Bitcoin::P::Tx.from_hash(new_tx)
|
63
|
+
|
64
|
+
new_tx.hash.should != tx.hash
|
65
|
+
new_tx.normalized_hash.size.should == 64
|
66
|
+
new_tx.normalized_hash.should == "402e30100b6937cc13828ca096377c93afc0ff227ad2f249245e5b1db9123a39"
|
67
|
+
end
|
68
|
+
|
52
69
|
it '#to_payload' do
|
53
70
|
tx = Tx.new( @payload[0] )
|
54
71
|
tx.to_payload.size.should == @payload[0].size
|
@@ -183,6 +200,53 @@ describe 'Tx' do
|
|
183
200
|
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json'))
|
184
201
|
outpoint_tx.hash.should == "a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954"
|
185
202
|
tx.verify_input_signature(0, outpoint_tx).should == true
|
203
|
+
|
204
|
+
# drop OP_CODESEPARATOR in subscript for signature_hash_for_input
|
205
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json'))
|
206
|
+
tx.hash.should == "46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa"
|
207
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json'))
|
208
|
+
outpoint_tx.hash.should == "bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224"
|
209
|
+
tx.verify_input_signature(0, outpoint_tx).should == true
|
210
|
+
|
211
|
+
# drop OP_CODESEPARATOR in subscript for signature_hash_for_input
|
212
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json'))
|
213
|
+
tx.hash.should == "aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8"
|
214
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json'))
|
215
|
+
outpoint_tx.hash.should == "326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e"
|
216
|
+
tx.verify_input_signature(0, outpoint_tx).should == true
|
217
|
+
|
218
|
+
# drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input
|
219
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json'))
|
220
|
+
tx.hash.should == "6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190"
|
221
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json'))
|
222
|
+
outpoint_tx.hash.should == "a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944"
|
223
|
+
tx.verify_input_signature(0, outpoint_tx).should == true
|
224
|
+
|
225
|
+
# drop multisig OP_CODESEPARATOR in subscript for signature_hash_for_input when used in ScriptSig
|
226
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json'))
|
227
|
+
tx.hash.should == "eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb"
|
228
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json'))
|
229
|
+
outpoint_tx.hash.should == "b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d"
|
230
|
+
tx.verify_input_signature(1, outpoint_tx).should == true
|
231
|
+
|
232
|
+
# OP_DUP OP_HASH160
|
233
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json'))
|
234
|
+
tx.hash.should == "5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f"
|
235
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json'))
|
236
|
+
outpoint_tx.hash.should == "b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9"
|
237
|
+
tx.verify_input_signature(0, outpoint_tx).should == true
|
238
|
+
outpoint_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json'))
|
239
|
+
outpoint_tx.hash.should == "ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742"
|
240
|
+
tx.verify_input_signature(1, outpoint_tx).should == true
|
241
|
+
|
242
|
+
# testnet3 e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009
|
243
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json'))
|
244
|
+
tx.hash.should == "e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009"
|
245
|
+
prev_txs = {}
|
246
|
+
tx.in.map{|i| i.previous_output }.uniq.each{|i| prev_txs[i] = Bitcoin::P::Tx.from_json(fixtures_file("tx-#{i}.json")) }
|
247
|
+
tx.in.each.with_index{|i,idx|
|
248
|
+
tx.verify_input_signature(idx, prev_txs[i.previous_output]).should == true
|
249
|
+
}
|
186
250
|
end
|
187
251
|
|
188
252
|
it '#sign_input_signature' do
|
@@ -244,6 +308,95 @@ describe 'Tx' do
|
|
244
308
|
prev_tx.hash.should == "52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2"
|
245
309
|
#File.open("rawtx-#{prev_tx.hash}.json",'wb'){|f| f.print prev_tx.to_json }
|
246
310
|
end
|
311
|
+
|
312
|
+
it "#legacy_sigops_count" do
|
313
|
+
Tx.new(@payload[0]).legacy_sigops_count.should == 2
|
314
|
+
Tx.new(@payload[1]).legacy_sigops_count.should == 2
|
315
|
+
Tx.new(@payload[2]).legacy_sigops_count.should == 2
|
316
|
+
|
317
|
+
# Test sig ops count in inputs too.
|
318
|
+
tx = Tx.new
|
319
|
+
txin = TxIn.new
|
320
|
+
txin.script_sig = Bitcoin::Script.from_string("10 OP_CHECKMULTISIGVERIFY OP_CHECKSIGVERIFY").to_binary
|
321
|
+
tx.add_in(txin)
|
322
|
+
txout = TxOut.new
|
323
|
+
txout.pk_script = Bitcoin::Script.from_string("5 OP_CHECKMULTISIG OP_CHECKSIG").to_binary
|
324
|
+
tx.add_out(txout)
|
325
|
+
tx.legacy_sigops_count.should == (20 + 1 + 20 + 1)
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
describe "Tx - is_final?" do
|
330
|
+
it "should be final if lock_time == 0" do
|
331
|
+
tx = Tx.new
|
332
|
+
tx.lock_time = 0
|
333
|
+
tx.is_final?(0,0).should == true
|
334
|
+
|
335
|
+
# even if has non-final input:
|
336
|
+
txin = TxIn.new
|
337
|
+
txin.sequence = "\x01\x00\x00\x00"
|
338
|
+
tx.add_in(txin)
|
339
|
+
tx.is_final?(0,0).should == true
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should be final if lock_time is below block_height" do
|
343
|
+
tx = Tx.new
|
344
|
+
txin = TxIn.new
|
345
|
+
txin.sequence = "\x01\x00\x00\x00"
|
346
|
+
tx.add_in(txin)
|
347
|
+
tx.lock_time = 6543
|
348
|
+
tx.is_final?(6000,0).should == false
|
349
|
+
tx.is_final?(6543,0).should == false # when equal to block height, still not final
|
350
|
+
tx.is_final?(6544,0).should == true
|
351
|
+
tx.is_final?(9999,0).should == true
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should be final if lock_time is below timestamp" do
|
355
|
+
tx = Tx.new
|
356
|
+
txin = TxIn.new
|
357
|
+
txin.sequence = "\xff\xff\xff\xff"
|
358
|
+
tx.add_in(txin)
|
359
|
+
txin = TxIn.new
|
360
|
+
txin.sequence = "\x01\x00\x00\x00"
|
361
|
+
tx.add_in(txin)
|
362
|
+
tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD # when equal, interpreted as threshold
|
363
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == false
|
364
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == false # when equal to timestamp, still not final
|
365
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
|
366
|
+
|
367
|
+
tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
|
368
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == false
|
369
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == false # when equal to timestamp, still not final
|
370
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should be final if all inputs are finalized regardless of lock_time" do
|
374
|
+
tx = Tx.new
|
375
|
+
txin = TxIn.new
|
376
|
+
txin.sequence = "\xff\xff\xff\xff"
|
377
|
+
tx.add_in(txin)
|
378
|
+
txin = TxIn.new
|
379
|
+
txin.sequence = "\xff\xff\xff\xff"
|
380
|
+
tx.add_in(txin)
|
381
|
+
|
382
|
+
tx.lock_time = 6543
|
383
|
+
tx.is_final?(6000,0).should == true
|
384
|
+
tx.is_final?(6543,0).should == true
|
385
|
+
tx.is_final?(6544,0).should == true
|
386
|
+
tx.is_final?(9999,0).should == true
|
387
|
+
|
388
|
+
tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD
|
389
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD - 1).should == true
|
390
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD).should == true
|
391
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
|
392
|
+
|
393
|
+
tx.lock_time = Bitcoin::LOCKTIME_THRESHOLD + 666
|
394
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 1).should == true
|
395
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 666).should == true
|
396
|
+
tx.is_final?(0,Bitcoin::LOCKTIME_THRESHOLD + 667).should == true
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
247
400
|
|
248
401
|
it '#calculate_minimum_fee' do
|
249
402
|
tx = Tx.new( fixtures_file('rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin') )
|
@@ -254,6 +407,23 @@ describe 'Tx' do
|
|
254
407
|
tx.minimum_block_fee.should == 10_000
|
255
408
|
end
|
256
409
|
|
410
|
+
it '#calculate_minimum_fee for litecoin' do
|
411
|
+
tx = Tx.from_json(fixtures_file('litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json'))
|
412
|
+
tx.minimum_relay_fee.should == 0
|
413
|
+
tx.minimum_block_fee.should == 30_000
|
414
|
+
Bitcoin.network = :litecoin # change to litecoin
|
415
|
+
tx.minimum_relay_fee.should == 0
|
416
|
+
tx.minimum_block_fee.should == 5_900_000
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should compare transactions" do
|
420
|
+
tx1 = Tx.new( @payload[0] )
|
421
|
+
tx2 = Tx.new( @payload[1] )
|
422
|
+
(tx1 == Bitcoin::P::Tx.from_json(tx1.to_json)).should == true
|
423
|
+
(tx1 == tx2).should == false
|
424
|
+
(tx1 == nil).should == false
|
425
|
+
end
|
426
|
+
|
257
427
|
describe "Tx - BIP Scripts" do
|
258
428
|
|
259
429
|
it "should do OP_CHECKMULTISIG" do
|
@@ -266,6 +436,11 @@ describe 'Tx' do
|
|
266
436
|
tx = Tx.from_json( fixtures_file('rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json') )
|
267
437
|
prev_tx = Tx.from_json( fixtures_file("rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json") )
|
268
438
|
tx.verify_input_signature(0, prev_tx).should == true
|
439
|
+
|
440
|
+
# checkmultisig for testnet3 tx: 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1 input index 1
|
441
|
+
tx = Tx.from_json( fixtures_file('tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json') )
|
442
|
+
prev_tx = Tx.from_json( fixtures_file("tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json") )
|
443
|
+
tx.verify_input_signature(1, prev_tx).should == true
|
269
444
|
end
|
270
445
|
|
271
446
|
it "should do P2SH with inner OP_CHECKMULTISIG (BIP 0016)" do
|
@@ -294,6 +469,14 @@ describe 'Tx' do
|
|
294
469
|
tx.verify_input_signature(0, prev_tx).should == true
|
295
470
|
end
|
296
471
|
|
297
|
-
|
472
|
+
it "should do OP_CHECKMULTISIG with OP_0 used as a pubkey" do
|
473
|
+
tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json'))
|
474
|
+
tx.hash.should == "6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba"
|
475
|
+
prev_tx = Bitcoin::P::Tx.from_json(fixtures_file('tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json'))
|
476
|
+
prev_tx.hash.should == "4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9"
|
477
|
+
tx.verify_input_signature(0, prev_tx).should == true
|
478
|
+
end
|
298
479
|
|
480
|
+
end
|
481
|
+
|
299
482
|
end
|
@@ -14,5 +14,32 @@ describe 'TxIn' do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
it "should compare txins" do
|
18
|
+
i1 = Tx.new(fixtures_file('rawtx-01.bin')).in[0]
|
19
|
+
i1_1 = TxIn.new(i1.prev_out, i1.prev_out_index, i1.script_sig_length, i1.script_sig)
|
20
|
+
i2 = Tx.new(fixtures_file('rawtx-02.bin')).in[0]
|
21
|
+
|
22
|
+
(i1 == i1).should == true
|
23
|
+
(i1 == i1_1).should == true
|
24
|
+
(i1 == i2).should == false
|
25
|
+
(i1 == nil).should == false
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be final only when sequence == 0xffffffff" do
|
29
|
+
txin = TxIn.new
|
30
|
+
txin.is_final?.should == true
|
31
|
+
txin.sequence.should == TxIn::DEFAULT_SEQUENCE
|
32
|
+
|
33
|
+
txin.sequence = "\x01\x00\x00\x00"
|
34
|
+
txin.is_final?.should == false
|
35
|
+
|
36
|
+
txin.sequence = "\x00\x00\x00\x00"
|
37
|
+
txin.is_final?.should == false
|
38
|
+
|
39
|
+
txin.sequence = "\xff\xff\xff\xff"
|
40
|
+
txin.is_final?.should == true
|
41
|
+
end
|
42
|
+
|
43
|
+
|
17
44
|
end
|
18
45
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative '../spec_helper.rb'
|
4
|
+
|
5
|
+
include Bitcoin::Protocol
|
6
|
+
|
7
|
+
describe 'TxOut' do
|
8
|
+
|
9
|
+
it '#initialize without specifying script_sig_length' do
|
10
|
+
key = Bitcoin::Key.generate
|
11
|
+
tx_out = TxOut.new(12345, Bitcoin::Script.from_string("OP_DUP OP_HASH160 #{key.hash160} OP_EQUALVERIFY OP_CHECKSIG").to_payload)
|
12
|
+
lambda { tx_out.to_payload }.should.not.raise
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should compare txouts" do
|
16
|
+
o1 = Tx.new(fixtures_file('rawtx-01.bin')).out[0]
|
17
|
+
o1_1 = TxOut.new(o1.value, o1.pk_script)
|
18
|
+
o2 = Tx.new(fixtures_file('rawtx-02.bin')).out[0]
|
19
|
+
|
20
|
+
(o1 == o1).should == true
|
21
|
+
(o1 == o1_1).should == true
|
22
|
+
(o1 == o2).should == false
|
23
|
+
(o1 == nil).should == false
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -358,6 +358,15 @@ describe "Bitcoin::Script OPCODES" do
|
|
358
358
|
[[1, 0], [1,1]],
|
359
359
|
].each{|stack, expected|
|
360
360
|
op(:pick, stack).should == expected
|
361
|
+
@script.invalid?.should == false
|
362
|
+
}
|
363
|
+
|
364
|
+
[
|
365
|
+
[[0], [0]],
|
366
|
+
[[-1], [-1]],
|
367
|
+
].each{|stack, expected|
|
368
|
+
op(:pick, stack).should == expected
|
369
|
+
@script.invalid?.should == true
|
361
370
|
}
|
362
371
|
end
|
363
372
|
|
@@ -367,9 +376,26 @@ describe "Bitcoin::Script OPCODES" do
|
|
367
376
|
[[1, 0], [1]],
|
368
377
|
].each{|stack, expected|
|
369
378
|
op(:roll, stack).should == expected
|
379
|
+
@script.invalid?.should == false
|
380
|
+
}
|
381
|
+
|
382
|
+
[
|
383
|
+
[[0], [0]],
|
384
|
+
[[-1], [-1]],
|
385
|
+
].each{|stack, expected|
|
386
|
+
op(:roll, stack).should == expected
|
387
|
+
@script.invalid?.should == true
|
370
388
|
}
|
371
389
|
end
|
372
390
|
|
391
|
+
it "should do op_2rot" do
|
392
|
+
op(:"2rot", [-1,0,1,2,3,4,5,6]).should == [-1, 0, 3, 4, 5, 6, 1, 2]
|
393
|
+
@script.invalid?.should == false
|
394
|
+
|
395
|
+
op(:"2rot", [2,3,4,5,6]).should == [2, 3, 4, 5, 6]
|
396
|
+
@script.invalid?.should == true
|
397
|
+
end
|
398
|
+
|
373
399
|
it "should do op_rot" do
|
374
400
|
op(:rot, [22, 21, 20]).should == [21, 20, 22]
|
375
401
|
op(:rot, [21, 20]).should == [21, 20]
|
@@ -443,6 +469,9 @@ describe "Bitcoin::Script OPCODES" do
|
|
443
469
|
"1 OP_DUP OP_IF OP_ELSE OP_ENDIF",
|
444
470
|
"1 OP_IF 1 OP_ELSE OP_ENDIF",
|
445
471
|
"0 OP_IF OP_ELSE 1 OP_ENDIF",
|
472
|
+
"beef OP_IF 1 OP_ELSE 0 OP_ENDIF",
|
473
|
+
"0 OP_NOTIF 1 OP_ELSE 0 OP_ENDIF",
|
474
|
+
"beef OP_NOTIF 0 OP_ELSE 1 OP_ENDIF",
|
446
475
|
].each{|script|
|
447
476
|
Bitcoin::Script.from_string(script).run.should == true
|
448
477
|
}
|
@@ -487,6 +516,11 @@ describe "Bitcoin::Script OPCODES" do
|
|
487
516
|
}
|
488
517
|
@script.op_checksig(verify_callback).should == [1]
|
489
518
|
|
519
|
+
@script.stack = [signature + hash_type, intger_pubkey=1]
|
520
|
+
verify_callback = proc{|pub,sig,hash_type|
|
521
|
+
pub.is_a?(String)
|
522
|
+
}
|
523
|
+
@script.op_checksig(verify_callback).should == [1]
|
490
524
|
|
491
525
|
@script.stack = [signature + hash_type, pubkey]
|
492
526
|
verify_callback = proc{|pub,sig,hash_type|
|
@@ -523,8 +557,8 @@ describe "Bitcoin::Script OPCODES" do
|
|
523
557
|
def run_script(string, hash)
|
524
558
|
script = Bitcoin::Script.from_string(string)
|
525
559
|
script.run do |pk, sig, hash_type|
|
526
|
-
k = Bitcoin::Key.new
|
527
|
-
k.verify(hash, sig) rescue false
|
560
|
+
k = Bitcoin::Key.new(nil, pk.unpack("H*")[0]) rescue false
|
561
|
+
k && k.verify(hash, sig) rescue false
|
528
562
|
end == true
|
529
563
|
end
|
530
564
|
|
@@ -593,6 +627,12 @@ describe "Bitcoin::Script OPCODES" do
|
|
593
627
|
script = "0 #{sig1} f0f0f0f0 #{sig3} 3 #{k1.pub} #{k2.pub} #{k3.pub} 3 OP_CHECKMULTISIG"
|
594
628
|
run_script(script, "foobar").should == false
|
595
629
|
|
630
|
+
script = "0 #{sig1} f0f0f0f0 #{sig3} 3 #{k1.pub} #{k2.pub} #{k3.pub} 3 OP_CHECKMULTISIG OP_NOT"
|
631
|
+
run_script(script, "foobar").should == true
|
632
|
+
|
633
|
+
script = "1 1 1 1 1 OP_CHECKMULTISIG OP_NOT"
|
634
|
+
run_script(script, "foobar").should == true
|
635
|
+
|
596
636
|
# mainnet tx output: 514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58
|
597
637
|
script = "0 #{sig1} 1 0 #{k1.pub} OP_SWAP OP_1ADD OP_CHECKMULTISIG"
|
598
638
|
run_script(script, "foobar").should == true
|
@@ -632,6 +672,12 @@ describe "Bitcoin::Script OPCODES" do
|
|
632
672
|
address = "3CkxTG25waxsmd13FFgRChPuGYba3ar36B"
|
633
673
|
script = Bitcoin::Script.new(Bitcoin::Script.to_address_script(address))
|
634
674
|
script.type.should == :p2sh
|
675
|
+
|
676
|
+
inner_script = Bitcoin::Script.from_string("0 OP_NOT").raw.unpack("H*")[0]
|
677
|
+
script_hash = Bitcoin.hash160(inner_script)
|
678
|
+
script = Bitcoin::Script.from_string("#{inner_script} OP_HASH160 #{script_hash} OP_EQUAL")
|
679
|
+
script.is_p2sh?.should == true
|
680
|
+
run_script(script.to_string, "foobar").should == true
|
635
681
|
end
|
636
682
|
|
637
683
|
it "should skip OP_EVAL" do
|
@@ -681,7 +727,19 @@ describe "Bitcoin::Script OPCODES" do
|
|
681
727
|
"0 OP_0NOTEQUAL 0 OP_EQUAL",
|
682
728
|
"2 82 OP_ADD 0 OP_EQUAL",
|
683
729
|
].each{|script|
|
684
|
-
Bitcoin::Script.from_string(script)
|
730
|
+
parsed_script = Bitcoin::Script.from_string(script)
|
731
|
+
result = parsed_script.run
|
732
|
+
#p [script, parsed_script, parsed_script.debug result]
|
733
|
+
result.should == true
|
734
|
+
}
|
735
|
+
|
736
|
+
[
|
737
|
+
"ffffff7f ffffff7f OP_ADD ffffff7f OP_ADD OP_TRUE"
|
738
|
+
].each{|script|
|
739
|
+
parsed_script = Bitcoin::Script.from_string(script)
|
740
|
+
result = parsed_script.run
|
741
|
+
#p [script, parsed_script, parsed_script.debug result]
|
742
|
+
result.should == false
|
685
743
|
}
|
686
744
|
end
|
687
745
|
|
@@ -699,4 +757,17 @@ describe "Bitcoin::Script OPCODES" do
|
|
699
757
|
}
|
700
758
|
end
|
701
759
|
|
760
|
+
it "check before casting and mark bad cases invalid" do
|
761
|
+
s = Bitcoin::Script.from_string("OP_NOT") # tries to pop off an element from the empty stack here.
|
762
|
+
s.run.should == false
|
763
|
+
s.invalid?.should == true
|
764
|
+
end
|
765
|
+
|
766
|
+
it "should do OP_CHECKSIGVERIFY and OP_CHECKMULTISIGVERIFY" do
|
767
|
+
tx1 = Bitcoin::P::Tx.new("0100000001a3fe4396b575690095bfc088d864aa971c99f65e2d893b48e0b26b1b60a28754000000006a47304402201ddfc8e3f825add9f42c0ce76dc5709cf76871e7ee6c97aae11d7db7f829b3f202201c3043515bfcf3d77845c8740ce4ccb4bda3f431da64f2596ee0ea2dfb727a5c01210328a5915165382c9b119d10d313c5781d98a7de79225f3c58e7fa115660ba90e0ffffffff0270f305000000000017a914ca164de1946bf0146ed1f32413df0efb0e1c730f87005d8806000000001976a91437c1d63690e00845663f3de661fef981c08e8de588ac00000000".htb)
|
768
|
+
tx2 = Bitcoin::P::Tx.new("0100000001a1c5263304aa47f8e4e8a8dbca33e525667f7f0d84390c5a92d49eccbe5b970f00000000fde50152483045022100fbc7ccd87ad2384a4d8823d3cf36d839bb6acca3d80a9ed9c51c784b7bdf1e430220305fcb1660219fcc340935000aa92dd02684b763177b8a3c1be094c919af323701473044022008f66d2e31175cdefbd7461afb5f9946e5dcb8173d1a2d3ef837f1c810695d160220250354de77b4a919b87910aa203ecec54bd1006d2dad2fcac06a54f39a9d39a101514d4f0176519c6375522103b124c48bbff7ebe16e7bd2b2f2b561aa53791da678a73d2777cc1ca4619ab6f72103ad6bb76e00d124f07a22680e39debd4dc4bdb1aa4b893720dd05af3c50560fdd52af67529c63552103b124c48bbff7ebe16e7bd2b2f2b561aa53791da678a73d2777cc1ca4619ab6f721025098a1d5a338592bf1e015468ec5a8fafc1fc9217feb5cb33597f3613a2165e9210360cfabc01d52eaaeb3976a5de05ff0cfa76d0af42d3d7e1b4c233ee8a00655ed2103f571540c81fd9dbf9622ca00cfe95762143f2eab6b65150365bb34ac533160432102bc2b4be1bca32b9d97e2d6fb255504f4bc96e01aaca6e29bfa3f8bea65d8865855af672103ad6bb76e00d124f07a22680e39debd4dc4bdb1aa4b893720dd05af3c50560fddada820a4d933888318a23c28fb5fc67aca8530524e2074b1d185dbf5b4db4ddb0642848868685174519c6351670068000000000170f30500000000001976a914bce2fe0e49630a996cb9fe611e6b9b7d1e4dc21188acb4ff6153".htb)
|
769
|
+
tx2.verify_input_signature(0, tx1).should == true
|
770
|
+
end
|
771
|
+
|
772
|
+
|
702
773
|
end
|