bitcoin-ruby 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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