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,517 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- # The storage implementation supports different backends, which inherit from
4
- # Storage::StoreBase and implement the same interface.
5
- # Each backend returns Storage::Models objects to easily access helper methods and metadata.
6
- #
7
- # The most stable backend is Backends::SequelStore, which uses sequel and can use all
8
- # kinds of SQL database backends.
9
- module Bitcoin::Storage
10
-
11
- autoload :Models, 'bitcoin/storage/models'
12
-
13
- @log = Bitcoin::Logger.create(:storage)
14
- def self.log; @log; end
15
-
16
- BACKENDS = [:dummy, :sequel, :utxo]
17
- BACKENDS.each do |name|
18
- module_eval <<-EOS
19
- def self.#{name} config, *args
20
- Backends.const_get("#{name.capitalize}Store").new(config, *args)
21
- end
22
- EOS
23
- end
24
-
25
- module Backends
26
-
27
- BACKENDS.each {|b| autoload("#{b.to_s.capitalize}Store", "bitcoin/storage/#{b}/#{b}_store.rb") }
28
-
29
- # Base class for storage backends.
30
- # Every backend must overwrite the "Not implemented" methods
31
- # and provide an implementation specific to the storage.
32
- # Also, before returning the objects, they should be wrapped
33
- # inside the appropriate Bitcoin::Storage::Models class.
34
- class StoreBase
35
-
36
- # main branch (longest valid chain)
37
- MAIN = 0
38
-
39
- # side branch (connected, valid, but too short)
40
- SIDE = 1
41
-
42
- # orphan branch (not connected to main branch / genesis block)
43
- ORPHAN = 2
44
-
45
- # possible script types
46
- SCRIPT_TYPES = [:unknown, :pubkey, :hash160, :multisig, :p2sh, :op_return]
47
- if Bitcoin.namecoin?
48
- [:name_new, :name_firstupdate, :name_update].each {|n| SCRIPT_TYPES << n }
49
- end
50
-
51
- # possible address types
52
- ADDRESS_TYPES = [:hash160, :p2sh]
53
-
54
- DEFAULT_CONFIG = {}
55
-
56
- attr_reader :log
57
-
58
- attr_accessor :config
59
-
60
- def initialize(config = {}, getblocks_callback = nil)
61
- # merge all the configuration defaults, keeping the most specific ones.
62
- store_ancestors = self.class.ancestors.select {|a| a.name =~ /StoreBase$/ }.reverse
63
- base = store_ancestors.reduce(store_ancestors[0]::DEFAULT_CONFIG) do |config, ancestor|
64
- config.merge(ancestor::DEFAULT_CONFIG)
65
- end
66
- @config = base.merge(self.class::DEFAULT_CONFIG).merge(config)
67
- @log = config[:log] || Bitcoin::Storage.log
68
- @log.level = @config[:log_level] if @config[:log_level]
69
- init_store_connection
70
- @getblocks_callback = getblocks_callback
71
- @checkpoints = Bitcoin.network[:checkpoints] || {}
72
- @watched_addrs = []
73
- @notifiers = {}
74
- end
75
-
76
- def init_store_connection
77
- end
78
-
79
- # name of the storage backend currently in use ("sequel" or "utxo")
80
- def backend_name
81
- self.class.name.split("::")[-1].split("Store")[0].downcase
82
- end
83
-
84
- # reset the store; delete all data
85
- def reset
86
- raise "Not implemented"
87
- end
88
-
89
- # check data consistency of the top +count+ blocks.
90
- def check_consistency count
91
- raise "Not implemented"
92
- end
93
-
94
-
95
- # handle a new block incoming from the network
96
- def new_block blk
97
- time = Time.now
98
- res = store_block(blk)
99
- log.info { "block #{blk.hash} " +
100
- "[#{res[0]}, #{['main', 'side', 'orphan'][res[1]]}] " +
101
- "(#{"%.4fs, %3dtx, %.3fkb" % [(Time.now - time), blk.tx.size, blk.payload.bytesize.to_f/1000]})" } if res && res[1]
102
- res
103
- end
104
-
105
- # store given block +blk+.
106
- # determine branch/chain and dept of block. trigger reorg if side branch becomes longer
107
- # than current main chain and connect orpans.
108
- def store_block blk
109
- log.debug { "new block #{blk.hash}" }
110
-
111
- existing = get_block(blk.hash)
112
- if existing && existing.chain == MAIN
113
- log.debug { "=> exists (#{existing.depth}, #{existing.chain})" }
114
- return [existing.depth]
115
- end
116
-
117
- prev_block = get_block(blk.prev_block.reverse_hth)
118
- unless @config[:skip_validation]
119
- validator = blk.validator(self, prev_block)
120
- validator.validate(rules: [:syntax], raise_errors: true)
121
- end
122
-
123
- if !prev_block || prev_block.chain == ORPHAN
124
- if blk.hash == Bitcoin.network[:genesis_hash]
125
- log.debug { "=> genesis (0)" }
126
- return persist_block(blk, MAIN, 0)
127
- else
128
- depth = prev_block ? prev_block.depth + 1 : 0
129
- log.debug { "=> orphan (#{depth})" }
130
- return [0, 2] unless (in_sync? || Bitcoin.network_name =~ /testnet/)
131
- return persist_block(blk, ORPHAN, depth)
132
- end
133
- end
134
- depth = prev_block.depth + 1
135
-
136
- checkpoint = @checkpoints[depth]
137
- if checkpoint && blk.hash != checkpoint
138
- log.warn "Block #{depth} doesn't match checkpoint #{checkpoint}"
139
- exit if depth > get_depth # TODO: handle checkpoint mismatch properly
140
- end
141
- if prev_block.chain == MAIN
142
- if prev_block == get_head
143
- log.debug { "=> main (#{depth})" }
144
- if !@config[:skip_validation] && ( !@checkpoints.any? || depth > @checkpoints.keys.last )
145
- if self.class.name =~ /UtxoStore/
146
- @config[:utxo_cache] = 0
147
- @config[:block_cache] = 120
148
- end
149
- validator.validate(rules: [:context], raise_errors: true)
150
- end
151
- res = persist_block(blk, MAIN, depth, prev_block.work)
152
- push_notification(:block, [blk, *res])
153
- return res
154
- else
155
- log.debug { "=> side (#{depth})" }
156
- return persist_block(blk, SIDE, depth, prev_block.work)
157
- end
158
- else
159
- head = get_head
160
- if prev_block.work + blk.block_work <= head.work
161
- log.debug { "=> side (#{depth})" }
162
- return persist_block(blk, SIDE, depth, prev_block.work)
163
- else
164
- log.debug { "=> reorg" }
165
- new_main, new_side = [], []
166
- fork_block = prev_block
167
- while fork_block.chain != MAIN
168
- new_main << fork_block.hash
169
- fork_block = fork_block.get_prev_block
170
- end
171
- b = fork_block
172
- while b = b.get_next_block
173
- new_side << b.hash
174
- end
175
- log.debug { "new main: #{new_main.inspect}" }
176
- log.debug { "new side: #{new_side.inspect}" }
177
-
178
- push_notification(:reorg, [ new_main, new_side ])
179
-
180
- reorg(new_side.reverse, new_main.reverse)
181
- return persist_block(blk, MAIN, depth, prev_block.work)
182
- end
183
- end
184
- end
185
-
186
- # persist given block +blk+ to storage.
187
- def persist_block(blk)
188
- raise "Not implemented"
189
- end
190
-
191
- # update +attrs+ for block with given +hash+.
192
- # typically used to update the chain value during reorg.
193
- def update_block(hash, attrs)
194
- raise "Not implemented"
195
- end
196
-
197
- def new_tx(tx)
198
- store_tx(tx)
199
- end
200
-
201
- # store given +tx+
202
- def store_tx(tx, validate = true)
203
- raise "Not implemented"
204
- end
205
-
206
- # check if block with given +blk_hash+ is already stored
207
- def has_block(blk_hash)
208
- raise "Not implemented"
209
- end
210
-
211
- # check if tx with given +tx_hash+ is already stored
212
- def has_tx(tx_hash)
213
- raise "Not implemented"
214
- end
215
-
216
- # get the hash of the leading block
217
- def get_head
218
- raise "Not implemented"
219
- end
220
-
221
- # return depth of the head block
222
- def get_depth
223
- raise "Not implemented"
224
- end
225
-
226
- # compute blockchain locator
227
- def get_locator pointer = get_head
228
- if @locator
229
- locator, head = @locator
230
- if head == pointer
231
- return locator
232
- end
233
- end
234
-
235
- return [("\x00"*32).hth] if get_depth == -1
236
- locator, step, orig_pointer = [], 1, pointer
237
- while pointer && pointer.hash != Bitcoin::network[:genesis_hash]
238
- locator << pointer.hash
239
- depth = pointer.depth - step
240
- break unless depth > 0
241
- prev_block = get_block_by_depth(depth) # TODO
242
- break unless prev_block
243
- pointer = prev_block
244
- step *= 2 if locator.size > 10
245
- end
246
- locator << Bitcoin::network[:genesis_hash]
247
- @locator = [locator, orig_pointer]
248
- locator
249
- end
250
-
251
- # get block with given +blk_hash+
252
- def get_block(blk_hash)
253
- raise "Not implemented"
254
- end
255
-
256
- # get block with given +depth+ from main chain
257
- def get_block_by_depth(depth)
258
- raise "Not implemented"
259
- end
260
-
261
- # get block with given +prev_hash+
262
- def get_block_by_prev_hash(prev_hash)
263
- raise "Not implemented"
264
- end
265
-
266
- # get block that includes tx with given +tx_hash+
267
- def get_block_by_tx(tx_hash)
268
- raise "Not implemented"
269
- end
270
-
271
- # get block by given +block_id+
272
- def get_block_by_id(block_id)
273
- raise "Not implemented"
274
- end
275
-
276
- # get block id in main chain by given +tx_id+
277
- def get_block_id_for_tx_id(tx_id)
278
- get_tx_by_id(tx_id).blk_id rescue nil # tx.blk_id is always in main chain
279
- end
280
-
281
- # get corresponding txin for the txout in
282
- # transaction +tx_hash+ with index +txout_idx+
283
- def get_txin_for_txout(tx_hash, txout_idx)
284
- raise "Not implemented"
285
- end
286
-
287
- # get an array of corresponding txins for provided +txouts+
288
- # txouts = [tx_hash, tx_idx]
289
- # can be overwritten by specific storage for opimization
290
- def get_txins_for_txouts(txouts)
291
- txouts.map{|tx_hash, tx_idx| get_txin_for_txout(tx_hash, tx_idx) }.compact
292
- end
293
-
294
- # get tx with given +tx_hash+
295
- def get_tx(tx_hash)
296
- raise "Not implemented"
297
- end
298
-
299
- # get more than one tx by +tx_hashes+, returns an array
300
- # can be reimplemented by specific storage for optimization
301
- def get_txs(tx_hashes)
302
- tx_hashes.map {|h| get_tx(h)}.compact
303
- end
304
-
305
- # get tx with given +tx_id+
306
- def get_tx_by_id(tx_id)
307
- raise "Not implemented"
308
- end
309
-
310
- # Grab the position of a tx in a given block
311
- def get_idx_from_tx_hash(tx_hash)
312
- raise "Not implemented"
313
- end
314
-
315
- # collect all txouts containing the
316
- # given +script+
317
- def get_txouts_for_pk_script(script)
318
- raise "Not implemented"
319
- end
320
-
321
- # collect all txouts containing a
322
- # standard tx to given +address+
323
- def get_txouts_for_address(address, unconfirmed = false)
324
- hash160 = Bitcoin.hash160_from_address(address)
325
- type = Bitcoin.address_type(address)
326
- get_txouts_for_hash160(hash160, type, unconfirmed)
327
- end
328
-
329
- # collect all unspent txouts containing a
330
- # standard tx to given +address+
331
- def get_unspent_txouts_for_address(address, unconfirmed = false)
332
- txouts = self.get_txouts_for_address(address, unconfirmed)
333
- txouts.select! do |t|
334
- not t.get_next_in
335
- end
336
- txouts
337
- end
338
-
339
- # get balance for given +hash160+
340
- def get_balance(hash160_or_addr, unconfirmed = false)
341
- if Bitcoin.valid_address?(hash160_or_addr)
342
- txouts = get_txouts_for_address(hash160_or_addr)
343
- else
344
- txouts = get_txouts_for_hash160(hash160_or_addr, :hash160, unconfirmed)
345
- end
346
- unspent = txouts.select {|o| o.get_next_in.nil?}
347
- unspent.map(&:value).inject {|a,b| a+=b; a} || 0
348
- rescue
349
- nil
350
- end
351
-
352
- # parse script and collect address/txout mappings to index
353
- def parse_script txout, i, tx_hash = "", tx_idx
354
- addrs, names = [], []
355
-
356
- script = Bitcoin::Script.new(txout.pk_script) rescue nil
357
- if script
358
- if script.is_hash160? || script.is_pubkey? || script.is_p2sh?
359
- addrs << [i, script.get_address]
360
- elsif script.is_multisig?
361
- script.get_multisig_addresses.map do |address|
362
- addrs << [i, address]
363
- end
364
- elsif Bitcoin.namecoin? && script.is_namecoin?
365
- addrs << [i, script.get_address]
366
- names << [i, script]
367
- elsif script.is_op_return?
368
- log.info { "Ignoring OP_RETURN script: #{script.get_op_return_data}" }
369
- else
370
- log.info { "Unknown script type in txout #{tx_hash}:#{tx_idx}" }
371
- log.debug { script.to_string }
372
- end
373
- script_type = SCRIPT_TYPES.index(script.type)
374
- else
375
- log.error { "Error parsing script #{tx_hash}:#{tx_idx}" }
376
- script_type = SCRIPT_TYPES.index(:unknown)
377
- end
378
- [script_type, addrs, names]
379
- end
380
-
381
- def add_watched_address address
382
- hash160 = Bitcoin.hash160_from_address(address)
383
- @db[:addr].insert(hash160: hash160) unless @db[:addr][hash160: hash160]
384
- @watched_addrs << hash160 unless @watched_addrs.include?(hash160)
385
- end
386
-
387
- def rescan
388
- raise "Not implemented"
389
- end
390
-
391
- # import satoshi bitcoind blk0001.dat blockchain file
392
- def import filename, max_depth = nil
393
- if File.file?(filename)
394
- log.info { "Importing #{filename}" }
395
- File.open(filename) do |file|
396
- until file.eof?
397
- magic = file.read(4)
398
-
399
- # bitcoind pads the ends of the block files so that it doesn't
400
- # have to reallocate space on every new block.
401
- break if magic == "\0\0\0\0"
402
- raise "invalid network magic" unless Bitcoin.network[:magic_head] == magic
403
-
404
- size = file.read(4).unpack("L")[0]
405
- blk = Bitcoin::P::Block.new(file.read(size))
406
- depth, chain = new_block(blk)
407
- break if max_depth && depth >= max_depth
408
- end
409
- end
410
- elsif File.directory?(filename)
411
- Dir.entries(filename).sort.each do |file|
412
- next unless file =~ /^blk.*?\.dat$/
413
- import(File.join(filename, file), max_depth)
414
- end
415
- else
416
- raise "Import dir/file #{filename} not found"
417
- end
418
- end
419
-
420
- def in_sync?
421
- (get_head && (Time.now - get_head.time).to_i < 3600) ? true : false
422
- end
423
-
424
- def push_notification channel, message
425
- @notifiers[channel.to_sym].push(message) if @notifiers[channel.to_sym]
426
- end
427
-
428
- def subscribe channel
429
- @notifiers[channel.to_sym] ||= EM::Channel.new
430
- @notifiers[channel.to_sym].subscribe {|*data| yield(*data) }
431
- end
432
-
433
- end
434
-
435
- class SequelStoreBase < StoreBase
436
-
437
- DEFAULT_CONFIG = {
438
- sqlite_pragmas: {
439
- # journal_mode pragma
440
- journal_mode: false,
441
- # synchronous pragma
442
- synchronous: false,
443
- # cache_size pragma
444
- # positive specifies number of cache pages to use,
445
- # negative specifies cache size in kilobytes.
446
- cache_size: -200_000,
447
- }
448
- }
449
-
450
- SEQUEL_ADAPTERS = { :sqlite => "sqlite3", :postgres => "pg", :mysql => "mysql" }
451
-
452
- #set the connection
453
- def init_store_connection
454
- return unless (self.is_a?(SequelStore) || self.is_a?(UtxoStore)) && @config[:db]
455
- @config[:db].sub!("~", ENV["HOME"])
456
- @config[:db].sub!("<network>", Bitcoin.network_name.to_s)
457
- adapter = SEQUEL_ADAPTERS[@config[:db].split(":").first] rescue nil
458
- Bitcoin.require_dependency(adapter, gem: adapter) if adapter
459
- connect
460
- end
461
-
462
- # connect to database
463
- def connect
464
- Sequel.extension(:core_extensions, :sequel_3_dataset_methods)
465
- @db = Sequel.connect(@config[:db].sub("~", ENV["HOME"]))
466
- @db.extend_datasets(Sequel::Sequel3DatasetMethods)
467
- sqlite_pragmas; migrate; check_metadata
468
- log.info { "opened #{backend_name} store #{@db.uri}" }
469
- end
470
-
471
- # check if schema is up to date and migrate to current version if necessary
472
- def migrate
473
- migrations_path = File.join(File.dirname(__FILE__), "#{backend_name}/migrations")
474
- Sequel.extension :migration
475
- unless Sequel::Migrator.is_current?(@db, migrations_path)
476
- store = self; log = @log; @db.instance_eval { @log = log; @store = store }
477
- Sequel::Migrator.run(@db, migrations_path)
478
- unless (v = @db[:schema_info].first) && v[:magic] && v[:backend]
479
- @db[:schema_info].update(
480
- magic: Bitcoin.network[:magic_head].hth, backend: backend_name)
481
- end
482
- end
483
- end
484
-
485
- # check that database network magic and backend match the ones we are using
486
- def check_metadata
487
- version = @db[:schema_info].first
488
- unless version[:magic] == Bitcoin.network[:magic_head].hth
489
- name = Bitcoin::NETWORKS.find{|n,d| d[:magic_head].hth == version[:magic]}[0]
490
- raise "Error: DB #{@db.url} was created for '#{name}' network!"
491
- end
492
- unless version[:backend] == backend_name
493
- if version[:backend] == "sequel" && backend_name == "utxo"
494
- log.warn { "Note: The 'utxo' store is now the default backend.
495
- To keep using the full storage, change the configuration to use storage: 'sequel::#{@db.url}'.
496
- To use the new storage backend, delete or move #{@db.url}, or specify a different database path in the config." }
497
- end
498
- raise "Error: DB #{@db.url} was created for '#{version[:backend]}' backend!"
499
- end
500
- end
501
-
502
- # set pragma options for sqlite (if it is sqlite)
503
- def sqlite_pragmas
504
- return unless (@db.is_a?(Sequel::SQLite::Database) rescue false)
505
- @config[:sqlite_pragmas].each do |name, value|
506
- @db.pragma_set name, value
507
- log.debug { "set sqlite pragma #{name} to #{value}" }
508
- end
509
- end
510
- end
511
-
512
- end
513
- end
514
-
515
-
516
- # TODO: someday sequel will support #blob directly and #to_sequel_blob will be gone
517
- class String; def blob; to_sequel_blob; end; end