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,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