bitcoin-ruby 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +2 -7
  4. data/COPYING +1 -1
  5. data/Gemfile +2 -6
  6. data/Gemfile.lock +34 -0
  7. data/README.rdoc +16 -68
  8. data/Rakefile +3 -6
  9. data/bin/bitcoin_shell +0 -1
  10. data/{concept-examples/blockchain-pow.rb → examples/concept-blockchain-pow.rb} +0 -0
  11. data/lib/bitcoin.rb +350 -296
  12. data/lib/bitcoin/builder.rb +3 -1
  13. data/lib/bitcoin/connection.rb +2 -1
  14. data/lib/bitcoin/contracthash.rb +76 -0
  15. data/lib/bitcoin/dogecoin.rb +97 -0
  16. data/lib/bitcoin/ffi/bitcoinconsensus.rb +74 -0
  17. data/lib/bitcoin/ffi/openssl.rb +98 -2
  18. data/lib/bitcoin/ffi/secp256k1.rb +144 -0
  19. data/lib/bitcoin/key.rb +12 -2
  20. data/lib/bitcoin/logger.rb +3 -12
  21. data/lib/bitcoin/protocol/block.rb +3 -9
  22. data/lib/bitcoin/protocol/parser.rb +6 -2
  23. data/lib/bitcoin/protocol/tx.rb +44 -13
  24. data/lib/bitcoin/protocol/txin.rb +4 -2
  25. data/lib/bitcoin/protocol/txout.rb +2 -2
  26. data/lib/bitcoin/script.rb +212 -37
  27. data/lib/bitcoin/trezor/mnemonic.rb +130 -0
  28. data/lib/bitcoin/version.rb +1 -1
  29. data/spec/bitcoin/bitcoin_spec.rb +32 -3
  30. data/spec/bitcoin/builder_spec.rb +18 -0
  31. data/spec/bitcoin/contracthash_spec.rb +45 -0
  32. data/spec/bitcoin/dogecoin_spec.rb +176 -0
  33. data/spec/bitcoin/ffi_openssl.rb +45 -0
  34. data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
  35. data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
  36. data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
  37. data/spec/bitcoin/fixtures/coinbase.json +24 -0
  38. data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  39. data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
  40. data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
  41. data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
  42. data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  43. data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  44. data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  45. data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  46. data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  47. data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  48. data/spec/bitcoin/protocol/block_spec.rb +0 -22
  49. data/spec/bitcoin/protocol/tx_spec.rb +145 -2
  50. data/spec/bitcoin/script/script_spec.rb +282 -0
  51. data/spec/bitcoin/secp256k1_spec.rb +48 -0
  52. data/spec/bitcoin/spec_helper.rb +0 -51
  53. data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
  54. metadata +48 -98
  55. data/bin/bitcoin_dns_seed +0 -130
  56. data/bin/bitcoin_gui +0 -80
  57. data/bin/bitcoin_node +0 -153
  58. data/bin/bitcoin_node_cli +0 -81
  59. data/bin/bitcoin_wallet +0 -402
  60. data/doc/CONFIG.rdoc +0 -66
  61. data/doc/EXAMPLES.rdoc +0 -13
  62. data/doc/NAMECOIN.rdoc +0 -34
  63. data/doc/NODE.rdoc +0 -225
  64. data/doc/STORAGE.rdoc +0 -33
  65. data/doc/WALLET.rdoc +0 -102
  66. data/examples/balance.rb +0 -66
  67. data/examples/forwarder.rb +0 -73
  68. data/examples/index_nhash.rb +0 -24
  69. data/examples/reindex_p2sh_addrs.rb +0 -44
  70. data/examples/relay_tx.rb +0 -22
  71. data/examples/verify_tx.rb +0 -57
  72. data/lib/bitcoin/config.rb +0 -58
  73. data/lib/bitcoin/gui/addr_view.rb +0 -44
  74. data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
  75. data/lib/bitcoin/gui/bitcoin-ruby.svg +0 -80
  76. data/lib/bitcoin/gui/conn_view.rb +0 -38
  77. data/lib/bitcoin/gui/connection.rb +0 -70
  78. data/lib/bitcoin/gui/em_gtk.rb +0 -30
  79. data/lib/bitcoin/gui/gui.builder +0 -1643
  80. data/lib/bitcoin/gui/gui.rb +0 -292
  81. data/lib/bitcoin/gui/helpers.rb +0 -115
  82. data/lib/bitcoin/gui/tree_view.rb +0 -84
  83. data/lib/bitcoin/gui/tx_view.rb +0 -69
  84. data/lib/bitcoin/namecoin.rb +0 -280
  85. data/lib/bitcoin/network/command_client.rb +0 -104
  86. data/lib/bitcoin/network/command_handler.rb +0 -570
  87. data/lib/bitcoin/network/connection_handler.rb +0 -387
  88. data/lib/bitcoin/network/node.rb +0 -565
  89. data/lib/bitcoin/storage/dummy/dummy_store.rb +0 -179
  90. data/lib/bitcoin/storage/models.rb +0 -171
  91. data/lib/bitcoin/storage/sequel/migrations.rb +0 -99
  92. data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +0 -52
  93. data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +0 -45
  94. data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +0 -18
  95. data/lib/bitcoin/storage/sequel/migrations/004_change_txin_prev_out_to_blob.rb +0 -18
  96. data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +0 -14
  97. data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +0 -31
  98. data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +0 -16
  99. data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +0 -31
  100. data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +0 -56
  101. data/lib/bitcoin/storage/sequel/sequel_store.rb +0 -551
  102. data/lib/bitcoin/storage/storage.rb +0 -517
  103. data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +0 -52
  104. data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +0 -18
  105. data/lib/bitcoin/storage/utxo/migrations/003_update_indices.rb +0 -14
  106. data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +0 -14
  107. data/lib/bitcoin/storage/utxo/utxo_store.rb +0 -374
  108. data/lib/bitcoin/validation.rb +0 -400
  109. data/lib/bitcoin/wallet/coinselector.rb +0 -33
  110. data/lib/bitcoin/wallet/keygenerator.rb +0 -77
  111. data/lib/bitcoin/wallet/keystore.rb +0 -207
  112. data/lib/bitcoin/wallet/txdp.rb +0 -118
  113. data/lib/bitcoin/wallet/wallet.rb +0 -281
  114. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
  115. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +0 -43
  116. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
  117. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +0 -67
  118. data/spec/bitcoin/namecoin_spec.rb +0 -182
  119. data/spec/bitcoin/node/command_api_spec.rb +0 -663
  120. data/spec/bitcoin/storage/models_spec.rb +0 -104
  121. data/spec/bitcoin/storage/reorg_spec.rb +0 -236
  122. data/spec/bitcoin/storage/storage_spec.rb +0 -387
  123. data/spec/bitcoin/storage/validation_spec.rb +0 -300
  124. data/spec/bitcoin/wallet/coinselector_spec.rb +0 -38
  125. data/spec/bitcoin/wallet/keygenerator_spec.rb +0 -69
  126. data/spec/bitcoin/wallet/keystore_spec.rb +0 -190
  127. data/spec/bitcoin/wallet/txdp_spec.rb +0 -76
  128. data/spec/bitcoin/wallet/wallet_spec.rb +0 -238
@@ -1,104 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require_relative '../spec_helper'
4
-
5
- include Bitcoin
6
- include Bitcoin::Storage
7
- include Bitcoin::Storage::Backends
8
- include Bitcoin::Builder
9
-
10
- Bitcoin::network = :testnet
11
- [
12
- # [:dummy],
13
- [:sequel, :sqlite],
14
- # [:utxo, :sqlite, index_all_addrs: true],
15
- [:sequel, :postgres],
16
- [:utxo, :postgres, index_all_addrs: true],
17
- [:sequel, :mysql],
18
- [:utxo, :mysql, index_all_addrs: true],
19
- ].compact.each do |options|
20
- next unless storage = setup_db(*options)
21
-
22
- describe "Storage::Models (#{options[0].to_s.capitalize}Store, #{options[1]})" do
23
-
24
- before do
25
- Bitcoin.network[:no_difficulty] = true
26
- Bitcoin.network[:proof_of_work_limit] = Bitcoin.encode_compact_bits("ff"*32)
27
-
28
- @store = storage
29
- def @store.in_sync?; true; end
30
- @store.reset
31
-
32
- @store.store_block(P::Block.new(fixtures_file('testnet/block_0.bin')))
33
- @store.store_block(P::Block.new(fixtures_file('testnet/block_1.bin')))
34
- @store.store_block(P::Block.new(fixtures_file('testnet/block_2.bin')))
35
- @store.store_block(P::Block.new(fixtures_file('testnet/block_3.bin')))
36
-
37
- unless @store.class.name =~ /UtxoStore/
38
- @store.store_tx(P::Tx.new(fixtures_file('rawtx-01.bin')), false)
39
- @store.store_tx(P::Tx.new(fixtures_file('rawtx-02.bin')), false)
40
- end
41
-
42
- @blk = P::Block.new(fixtures_file('testnet/block_4.bin'))
43
- @tx = P::Tx.new(fixtures_file('rawtx-03.bin'))
44
- end
45
-
46
- after do
47
- Bitcoin.network.delete :no_difficulty
48
- end
49
-
50
- describe "Block" do
51
-
52
- before { @block = @store.get_block_by_depth(1) }
53
-
54
- it "should get prev block" do
55
- @block.get_prev_block.should == @store.get_block_by_depth(0)
56
- end
57
-
58
- it "should get next block" do
59
- @block.get_next_block.should == @store.get_block_by_depth(2)
60
- end
61
-
62
- it "should get total out" do
63
- @block.total_out.should == 5000000000
64
- end
65
-
66
- it "should get total in" do
67
- @block.total_in.should == 5000000000
68
- end
69
-
70
- it "should get total fee" do
71
- @block.total_fee.should == 0
72
- end
73
-
74
- end
75
-
76
- describe "Tx" do
77
-
78
- before { @tx = @store.get_block_by_depth(1).tx[0] }
79
-
80
- it "should get block" do
81
- @tx.get_block.should == @store.get_block_by_depth(1)
82
- end
83
-
84
- it "should get confirmations" do
85
- @tx.confirmations.should == 3
86
- end
87
-
88
- it "should get total out" do
89
- @tx.total_out.should == 5000000000
90
- end
91
-
92
- it "should get total in" do
93
- @tx.total_in.should == 5000000000
94
- end
95
-
96
- it "should get fee" do
97
- @tx.fee.should == 0
98
- end
99
-
100
- end
101
-
102
- end
103
-
104
- end
@@ -1,236 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require_relative '../spec_helper'
4
-
5
- include Bitcoin::Builder
6
-
7
- Bitcoin.network = :testnet
8
-
9
- [
10
- [:utxo, :sqlite, index_all_addrs: true],
11
- [:sequel, :sqlite], # [:sequel, :postgres],
12
- [:utxo, :postgres, index_all_addrs: true],
13
- [:sequel, :mysql],
14
- [:utxo, :mysql, index_all_addrs: true],
15
- ].compact.each do |options|
16
-
17
- next unless storage = setup_db(*options)
18
-
19
- describe "reorg (#{options[0]} - #{options[1]})" do
20
-
21
- def balance addr
22
- @store.get_balance(Bitcoin.hash160_from_address(addr))
23
- end
24
-
25
- before do
26
- @store = storage
27
- @store.reset
28
- def @store.in_sync?; true; end
29
-
30
- Bitcoin.network = :testnet
31
- Bitcoin.network[:retarget_interval] = 10
32
- Bitcoin.network[:proof_of_work_limit] = Bitcoin.encode_compact_bits("ff"*32)
33
-
34
- @key = Bitcoin::Key.generate
35
- @block0 = create_block "00"*32, false, [], @key
36
- Bitcoin.network[:genesis_hash] = @block0.hash
37
-
38
- @store.store_block(@block0)
39
- @store.get_head.should == @block0
40
- end
41
-
42
- it "should retarget" do
43
- @store.reset
44
- time = Time.now.to_i - 3000*600
45
-
46
- # create genesis block
47
- block = create_block "00"*32, false, [], @key, 50e8, {time: time}
48
- Bitcoin.network[:genesis_hash] = block.hash
49
- @store.store_block(block)
50
- time += 600
51
-
52
- # create too fast blocks
53
- block = create_blocks block.hash, 9, time: time, interval: 10
54
- time += 90
55
-
56
- -> { create_blocks block.hash, 1, time: time }
57
- .should.raise(Bitcoin::Validation::ValidationError).message.should =~ /difficulty/
58
-
59
- block = create_blocks block.hash, 1, time: time, bits: bits = 541065152
60
- @store.get_head.should == block
61
- time += 600
62
-
63
- # create too slow blocks
64
- block = create_blocks block.hash, 9, time: time, interval: 6000, bits: bits
65
- time += 8*6000
66
- -> { create_blocks block.hash, 1, time: time, bits: bits }
67
- .should.raise(Bitcoin::Validation::ValidationError).message.should =~ /difficulty/
68
-
69
- block = create_blocks block.hash, 1, bits: 553713663
70
- @store.get_head.should == block
71
- end
72
-
73
- it "should reorg across a retargetting boundary correctly" do
74
- @store.reset
75
- time = Time.now.to_i - 3000*600
76
-
77
- # create genesis block
78
- block = create_block "00"*32, false, [], @key, 50e8, {time: time}
79
- time += 600
80
- Bitcoin.network[:genesis_hash] = block.hash
81
- @store.store_block(block)
82
-
83
- # create first regular block
84
- split_block = create_blocks block.hash, 1, time: time
85
- split_time = time + 600
86
-
87
- # create branch A with target interval
88
- block_a = create_blocks split_block.hash, 8, time: split_time
89
- time_a = split_time + 8 * 600
90
-
91
- # create branch B with faster-than-target interval
92
- block_b = create_blocks split_block.hash, 8, time: split_time, interval: 60
93
- time_b = split_time + 8 * 60
94
-
95
- # create 2 blocks for branch A with regular difficulty
96
- block_a = create_blocks block_a.hash, 2, time: time_a
97
-
98
- # create 1 block for branch B at higher difficulty
99
- block_b = create_blocks block_b.hash, 1, time: time_b, bits: 541568460
100
-
101
- # check that shorter branch B has overtaken longer branch A due to more work
102
- @store.get_head.hash.should == block_b.hash
103
- end
104
-
105
- it "should validate duplicate tx in a side chain" do
106
- block1 = create_block @block0.hash, true, [], @key
107
-
108
- block_2_0 = create_block block1.hash, false, [ ->(t) {
109
- t.input {|i| i.prev_out block1.tx[0], 0; i.signature_key @key }
110
- t.output {|o| o.value 50e8; o.script {|s| s.recipient @key.addr } }
111
- }], @key
112
-
113
- @store.store_block(block_2_0).should == [2, 0]
114
-
115
- block_3_0 = create_block block_2_0.hash, false, [->(t) {
116
- t.input {|i| i.prev_out block_2_0.tx[1], 0; i.signature_key @key }
117
- t.output {|o| o.value 50e8; o.script {|s| s.recipient @key.addr } }
118
- }], @key
119
- @store.store_block(block_3_0).should == [3, 0]
120
-
121
- block_2_1 = create_block block1.hash, false
122
- block_2_1.tx << block_2_0.tx[1]
123
- block_2_1.recalc_mrkl_root
124
- block_2_1.recalc_block_hash
125
- @store.store_block(block_2_1).should == [2, 1]
126
-
127
- block_3_1 = create_block block_2_1.hash, false
128
- block_3_1.tx << block_3_0.tx[1]
129
- block_3_1.recalc_mrkl_root
130
- block_3_1.recalc_block_hash
131
-
132
- @store.store_block(block_3_1).should == [3, 1]
133
-
134
- block_4 = create_block block_3_1.hash, false
135
- @store.store_block(block_4).should == [4, 0]
136
- end
137
-
138
- it "should reorg a single side block" do
139
- @store.get_head.should == @block0
140
-
141
- block1 = create_block @block0.hash
142
- @store.get_head.should == block1
143
-
144
- block2_0 = create_block block1.hash
145
- @store.get_head.should == block2_0
146
-
147
- block2_1 = create_block block1.hash
148
- @store.get_head.should == block2_0
149
-
150
- block3 = create_block block2_1.hash
151
- @store.get_head.should == block3
152
- @store.get_block_by_depth(2).hash.should == block2_1.hash
153
- end
154
-
155
- it "should reorg two side blocks" do
156
- block1 = create_block @block0.hash
157
- @store.get_head.should == block1
158
-
159
- block2_0 = create_block block1.hash
160
- @store.get_head.should == block2_0
161
-
162
- block2_1 = create_block block1.hash
163
- @store.get_head.should == block2_0
164
-
165
- block3_1 = create_block block2_1.hash
166
- @store.get_head.should == block3_1
167
-
168
- block3_0 = create_block block2_0.hash
169
- @store.get_head.should == block3_1
170
-
171
- block4 = create_block block3_0.hash
172
- @store.get_head.should == block4
173
- end
174
-
175
- it "should reconnect orphans" do
176
- next(true.should == true) if @store.class.name =~ /Utxo/
177
- blocks = [@block0]
178
- 3.times { blocks << create_block(blocks.last.hash, false) }
179
-
180
- {
181
- [0, 1, 2, 3] => [0, 1, 2, 3],
182
- [0, 1, 3, 2] => [0, 1, 1, 3],
183
- [0, 3, 2, 1] => [0, 0, 0, 3],
184
- [0, 3, 1, 2] => [0, 0, 1, 3],
185
- [0, 2, 3, 1] => [0, 0, 0, 3],
186
- }.each do |order, result|
187
- @store.reset
188
- order.each_with_index do |n, i|
189
- @store.store_block(blocks[n])
190
- @store.get_head.should == blocks[result[i]]
191
- end
192
- end
193
-
194
- i = 3; (0..i).to_a.permutation.each do |order|
195
- @store.reset
196
- order.each {|n| @store.store_block(blocks[n]) }
197
- @store.get_head.should == blocks[i]
198
- end
199
- end
200
-
201
- it "should handle existing blocks" do
202
- blocks = [@block0]
203
- 3.times { blocks << create_block(blocks.last.hash, false) }
204
- blocks[1..-1].each.with_index {|b, idx| @store.store_block(b).should == [idx+1, 0] }
205
- 3.times {|i| @store.store_block(blocks[i]).should == [i] }
206
- @store.get_head.should == blocks[-1]
207
- end
208
-
209
- # see https://bitcointalk.org/index.php?topic=46370.0
210
- it "should pass reorg unit tests" do
211
- Bitcoin.network = :bitcoin
212
- # Disable difficulty check
213
- Bitcoin.network[:no_difficulty] = true
214
- @store.import "./spec/bitcoin/fixtures/reorg/blk_0_to_4.dat"
215
- @store.get_depth.should == 4
216
- @store.get_head.hash.should =~ /000000002f264d65040/
217
- balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 10000000000
218
- balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 0
219
- balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 5000000000
220
- balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 10000000000
221
- @store.import "./spec/bitcoin/fixtures/reorg/blk_3A.dat"
222
- @store.import "./spec/bitcoin/fixtures/reorg/blk_4A.dat"
223
- @store.get_head.hash.should =~ /000000002f264d65040/
224
- @store.import "./spec/bitcoin/fixtures/reorg/blk_5A.dat"
225
- @store.get_depth.should == 5
226
- @store.get_head.hash.should =~ /00000000195f85184e7/
227
- balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 15000000000
228
- balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 1000000000
229
- balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 0
230
- balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 14000000000
231
- Bitcoin.network.delete :no_difficulty
232
- Bitcoin.network = :testnet
233
- end
234
-
235
- end
236
- end
@@ -1,387 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require_relative '../spec_helper'
4
-
5
- include Bitcoin
6
- include Bitcoin::Storage
7
- include Bitcoin::Storage::Backends
8
- include Bitcoin::Builder
9
- include Bitcoin::Validation
10
-
11
- Bitcoin::network = :testnet
12
- [
13
- [:dummy],
14
- [:sequel, :sqlite],
15
- [:utxo, :sqlite, index_all_addrs: true],
16
- [:sequel, :postgres],
17
- [:utxo, :postgres, index_all_addrs: true],
18
- [:sequel, :mysql],
19
- [:utxo, :mysql, index_all_addrs: true],
20
- ].compact.each do |options|
21
-
22
- next unless storage = setup_db(*options)
23
-
24
- describe "Storage::Backends::#{options[0].to_s.capitalize}Store (#{options[1]})" do
25
-
26
- before do
27
- Bitcoin.network[:no_difficulty] = true
28
- Bitcoin.network[:proof_of_work_limit] = Bitcoin.encode_compact_bits("ff"*32)
29
-
30
- @store = storage
31
- def @store.in_sync?; true; end
32
- @store.reset
33
-
34
- @store.store_block(P::Block.new(fixtures_file('testnet/block_0.bin')))
35
- @store.store_block(P::Block.new(fixtures_file('testnet/block_1.bin')))
36
- @store.store_block(P::Block.new(fixtures_file('testnet/block_2.bin')))
37
- @store.store_block(P::Block.new(fixtures_file('testnet/block_3.bin')))
38
-
39
- unless @store.class.name =~ /UtxoStore/
40
- @store.store_tx(P::Tx.new(fixtures_file('rawtx-01.bin')), false)
41
- @store.store_tx(P::Tx.new(fixtures_file('rawtx-02.bin')), false)
42
- end
43
-
44
- @blk = P::Block.new(fixtures_file('testnet/block_4.bin'))
45
- @tx = P::Tx.new(fixtures_file('rawtx-03.bin'))
46
- end
47
-
48
- after do
49
- Bitcoin.network.delete :no_difficulty
50
- end
51
-
52
- it "should get backend name" do
53
- @store.backend_name.should == options[0].to_s
54
- end
55
-
56
- it "should get depth" do
57
- @store.get_depth.should == 3
58
- end
59
-
60
- it "should report depth as -1 if store is empty" do
61
- @store.reset
62
- @store.get_depth.should == -1
63
- end
64
-
65
- it "should get head" do
66
- @store.get_head
67
- .should == @store.get_block("0000000098932356a236718829dd9e3eb0f9143317ab921333b1a203de336de4")
68
- end
69
-
70
- it "should get locator" do
71
- @store.get_locator.should == [
72
- "0000000098932356a236718829dd9e3eb0f9143317ab921333b1a203de336de4",
73
- "000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f",
74
- "000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604",
75
- "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"]
76
- end
77
-
78
- it "should not store if there is no prev block" do
79
- @store.reset
80
- @store.store_block(@blk).should == [0, 2]
81
- @store.get_depth.should == -1
82
- end
83
-
84
- it "should check whether block is already stored" do
85
- @store.has_block(@blk.hash).should == false
86
- @store.store_block(@blk)
87
- @store.has_block(@blk.hash).should == true
88
- end
89
-
90
- it "should get block by depth" do
91
- @store.get_block_by_depth(0).hash.should ==
92
- P::Block.new(fixtures_file('testnet/block_0.bin')).hash
93
- @store.get_block_by_depth(1).hash.should ==
94
- P::Block.new(fixtures_file('testnet/block_1.bin')).hash
95
- @store.get_block_by_depth(2).hash.should ==
96
- P::Block.new(fixtures_file('testnet/block_2.bin')).hash
97
- end
98
-
99
- it "should store and retrieve all relevant block data for hash/json serialization" do
100
- (0..2).each do |i|
101
- expected = P::Block.new(fixtures_file("testnet/block_#{i}.bin")).to_hash
102
- @store.get_block_by_depth(i).to_hash.should == expected
103
- end
104
- end
105
-
106
- it "should get block by hash" do
107
- @store.get_block(
108
- "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008").hash
109
- .should == P::Block.new(fixtures_file('testnet/block_0.bin')).hash
110
- @store.get_block(
111
- "000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604").hash
112
- .should == P::Block.new(fixtures_file('testnet/block_1.bin')).hash
113
- @store.get_block(
114
- "000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f").hash
115
- .should == P::Block.new(fixtures_file('testnet/block_2.bin')).hash
116
- end
117
-
118
- it "should not get block" do
119
- @store.get_block("nonexistant").should == nil
120
- end
121
-
122
- it "should get block depth" do
123
- @store.get_block("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008")
124
- .depth.should == 0
125
- @store.get_block("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604")
126
- .depth.should == 1
127
- @store.get_block("000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f")
128
- .depth.should == 2
129
- end
130
-
131
- it "should get prev block" do
132
- @store.get_block("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008")
133
- .get_prev_block.should == nil
134
- @store.get_block("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604")
135
- .get_prev_block.should ==
136
- @store.get_block("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008")
137
- end
138
-
139
- it "should get next block" do
140
- @store.get_block("0000000098932356a236718829dd9e3eb0f9143317ab921333b1a203de336de4")
141
- .get_next_block.should == nil
142
- @store.get_block("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008")
143
- .get_next_block.should ==
144
- @store.get_block("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604")
145
- end
146
-
147
- it "should get block for tx" do
148
- @store.store_block(@blk)
149
- @store.get_block_by_tx(@blk.tx[0].hash).should == @blk
150
- end
151
-
152
- it "should get block id for tx id" do
153
- @store.store_block(@blk)
154
- tx = @store.get_tx(@blk.tx[0].hash)
155
- @store.get_block_id_for_tx_id(tx.id).should == @store.get_block(@blk.hash).id
156
- end
157
-
158
- unless @store.backend_name == 'utxo'
159
- describe :transactions do
160
-
161
- it "should store tx" do
162
- @store.store_tx(@tx, false).should != false
163
- end
164
-
165
- it "should not store tx if already stored and return existing id" do
166
- id = @store.store_tx(@tx, false)
167
- @store.store_tx(@tx, false).should == id
168
- end
169
-
170
- it "should check if tx is already stored" do
171
- @store.has_tx(@tx.hash).should == false
172
- @store.store_tx(@tx, false)
173
- @store.has_tx(@tx.hash).should == true
174
- end
175
-
176
- it "should store hash160 for txout" do
177
- @store.store_tx(@tx, false)
178
- @store.get_tx(@tx.hash).out[0].hash160
179
- .should == "3129d7051d509424d23d533fa2d5258977e822e3"
180
- end
181
-
182
- it "should get tx" do
183
- @store.store_tx(@tx, false)
184
- @store.get_tx(@tx.hash).should == @tx
185
- end
186
-
187
- it "should not get tx" do
188
- @store.get_tx("nonexistant").should == nil
189
- end
190
-
191
- it "should get the position for a given tx" do
192
- @store.store_block(@blk)
193
- result = @store.get_idx_from_tx_hash(@blk.tx[0].hash)
194
- result.should == 0
195
- end
196
-
197
- it "should get tx for txin" do
198
- @store.store_tx(@tx, false)
199
- @store.get_tx(@tx.hash).in[0].get_tx.should == @tx
200
- end
201
-
202
- it "should get prev out for txin" do
203
- tx = P::Tx.new(fixtures_file('rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin'))
204
- outpoint_tx = P::Tx.new(fixtures_file('rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin'))
205
- @store.store_tx(outpoint_tx, false)
206
- @store.store_tx(tx, false)
207
- @store.get_tx(tx.hash).in[0].get_prev_out.should == outpoint_tx.out[0]
208
- end
209
-
210
- it "should get tx for txout" do
211
- @store.store_tx(@tx, false)
212
- @store.get_tx(@tx.hash).out[0].get_tx.should == @tx
213
- end
214
-
215
- it "should get next in for txin" do
216
- tx = P::Tx.new(fixtures_file('rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin'))
217
- outpoint_tx = P::Tx.new(fixtures_file('rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin'))
218
- @store.store_tx(outpoint_tx, false)
219
- @store.store_tx(tx, false)
220
- @store.get_tx(outpoint_tx.hash).out[0].get_next_in.should == tx.in[0]
221
- end
222
-
223
- it "should store multisig tx and index hash160's" do
224
- keys = Array.new(2) { Bitcoin::Key.generate }
225
- pk_script = Bitcoin::Script.to_multisig_script(1, keys[0].pub, keys[1].pub)
226
- txout = P::TxOut.new(1000, pk_script)
227
- @tx.out[0] = txout
228
- @store.store_tx(@tx, false)
229
- keys.each do |key|
230
- hash160 = Bitcoin.hash160(key.pub)
231
- txouts = @store.get_txouts_for_hash160(hash160, :hash160, true)
232
- txouts.size.should == 1
233
- txouts[0].pk_script.should == txout.pk_script
234
- end
235
- end
236
-
237
- it "should index output script type" do
238
- @store.store_tx(@tx, false)
239
- @store.get_tx(@tx.hash).out.first.type.should == :hash160
240
- end
241
-
242
- end
243
- end
244
-
245
-
246
- describe :txouts do
247
-
248
- before do
249
- @key = Key.generate
250
- @key2 = Key.generate
251
- @store.store_block(@blk)
252
- blk = create_block @blk.hash, true, [], @key
253
- @block = create_block blk.hash, true, [->(t) {
254
- create_tx(t, blk.tx.first, 0, [[50, @key2]]) }], @key
255
- end
256
-
257
- it "should get block for tx" do
258
- @store.get_tx(@block.tx[1].hash).get_block.hash.should == @block.hash
259
- end
260
-
261
- it "should get txouts for pk script" do
262
- script = @blk.tx[0].out[0].pk_script
263
- @store.get_txouts_for_pk_script(script)
264
- .should == [@blk.tx[0].out[0]]
265
- end
266
-
267
- it "should get txouts for hash160" do
268
- @store.get_txouts_for_hash160(@key2.hash160, :hash160, true)
269
- .should == [@block.tx[1].out[0]]
270
- end
271
-
272
- it "should get txouts for address" do
273
- @store.get_txouts_for_address(@key2.addr, true)
274
- .should == [@block.tx[1].out[0]]
275
- end
276
-
277
- it "should get txouts for txin" do
278
- prev_tx = @block.tx[0]
279
- tx = build_tx { |t| create_tx(t, prev_tx, 0, [[prev_tx.out[0].value, Bitcoin::Key.generate]], @key) }
280
- @store.get_txout_for_txin(tx.in[0]).should == prev_tx.out[0]
281
- end
282
-
283
- it "should get unspent txouts for address" do
284
- @store.get_unspent_txouts_for_address(@key2.addr, true)
285
- .should == [@block.tx[1].out[0]]
286
- @block2 = create_block @block.hash, true, [->(t) {
287
- create_tx(t, @block.tx[1], 0, [[20, @key2]], @key2) }], @key
288
- @store.get_unspent_txouts_for_address(@key2.addr, true)
289
- .should == [@block2.tx[1].out[0]]
290
- end
291
-
292
- it "should get balance for address" do
293
- @store.get_balance(@key2.addr).should == 50
294
- @store.get_balance(@key2.hash160).should == 50
295
- end
296
-
297
- it "should get txouts for p2sh address (and not confuse regular and p2sh-type hash160" do
298
- block = create_block(@block.hash, false, [], @key)
299
-
300
- tx = build_tx do |t|
301
- t.input {|i| i.prev_out(@block.tx[1], 0); i.signature_key(@key2) }
302
- t.output do |o|
303
- o.value 10
304
- o.to @key2.hash160, :p2sh
305
- end
306
- t.output do |o|
307
- o.value 10
308
- o.to @key2.addr
309
- end
310
- end
311
- block.tx << tx; block.recalc_mrkl_root; block.recalc_block_hash
312
-
313
- @store.store_block(block)
314
-
315
- p2sh_address = Bitcoin.hash160_to_p2sh_address(@key2.hash160)
316
- o1 = @store.get_unspent_txouts_for_address(@key2.addr)
317
- o2 = @store.get_unspent_txouts_for_address(p2sh_address)
318
-
319
- o1.size.should == 1
320
- o2.size.should == 1
321
- o1.should != o2
322
- end
323
-
324
- end
325
-
326
- describe "validation" do
327
-
328
- before do
329
- @key = Bitcoin::Key.generate
330
- @store.store_block @blk
331
- @block = create_block @blk.hash, false, [], @key
332
- @tx = build_tx {|t| create_tx(t, @block.tx.first, 0, [[50, @key]]) }
333
- @tx.instance_eval { @in = [] }
334
- end
335
-
336
- it "should validate blocks" do
337
- @block.tx << @tx
338
- -> { @store.store_block(@block) }.should
339
- .raise(ValidationError).message.should =~ /mrkl_root/
340
- end
341
-
342
- it "should validate transactions for blocks added to main chain" do
343
- @store.store_block(@block)
344
- block = create_block @block.hash, false, [->(tx) {
345
- create_tx(tx, @block.tx.first, 0, [[50, @key]]) }], @key
346
- block.tx.last.in[0].prev_out_index = 5
347
- -> { @store.store_block(block) }.should
348
- .raise(ValidationError).message.should =~ /transactions_syntax/
349
- end
350
-
351
- it "should not validate transactions for blocks added to a side or orphan chain" do
352
- @store.store_block(@block)
353
- block = create_block @blk.hash, false, [->(tx) {
354
- create_tx(tx, @block.tx.first, 0, [[50, @key]]) }], @key
355
- @store.store_block(block).should == [5, 1]
356
- end
357
-
358
- if @store.class.name =~ /Sequel/
359
-
360
- it "should validate transactions" do
361
- @store.store_block @block
362
- -> { @store.store_tx(@tx, true) }.should.raise(ValidationError)
363
- end
364
-
365
-
366
- it "should validate transactions for new main blocks on reorg" do
367
- @store.store_block(@block)
368
- block = create_block @blk.hash, true, [->(tx) {
369
- create_tx(tx, @block.tx.first, 0, [[50, @key]]) }], @key
370
- block2 = create_block block.hash, false, [], @key
371
- -> { @store.store_block(block2) }.should
372
- .raise(ValidationError).message.should =~ /transactions_context/
373
- end
374
-
375
- end
376
-
377
- it "should skip validation" do
378
- @store.config[:skip_validation] = true
379
- @block.tx << @tx
380
- @store.store_block(@block).should == [5, 0]
381
- end
382
-
383
- end
384
-
385
- end
386
-
387
- end