bitcoin-ruby 0.0.1 → 0.0.2

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 (136) hide show
  1. data/.gitignore +4 -1
  2. data/Gemfile +21 -0
  3. data/README.rdoc +85 -25
  4. data/Rakefile +7 -3
  5. data/bin/bitcoin_node +39 -42
  6. data/bin/bitcoin_shell +1 -0
  7. data/bin/bitcoin_wallet +129 -53
  8. data/bitcoin-ruby.gemspec +4 -7
  9. data/concept-examples/blockchain-pow.rb +1 -1
  10. data/doc/CONFIG.rdoc +5 -5
  11. data/doc/EXAMPLES.rdoc +9 -5
  12. data/doc/NAMECOIN.rdoc +34 -0
  13. data/doc/NODE.rdoc +147 -10
  14. data/examples/balance.rb +10 -4
  15. data/examples/bbe_verify_tx.rb +7 -2
  16. data/examples/forwarder.rb +73 -0
  17. data/examples/generate_tx.rb +34 -0
  18. data/examples/simple_network_monitor_and_util.rb +187 -0
  19. data/examples/verify_tx.rb +1 -1
  20. data/lib/bitcoin.rb +308 -18
  21. data/lib/bitcoin/builder.rb +62 -36
  22. data/lib/bitcoin/config.rb +2 -0
  23. data/lib/bitcoin/connection.rb +11 -8
  24. data/lib/bitcoin/electrum/mnemonic.rb +162 -0
  25. data/lib/bitcoin/ffi/openssl.rb +187 -21
  26. data/lib/bitcoin/gui/addr_view.rb +2 -0
  27. data/lib/bitcoin/gui/conn_view.rb +2 -0
  28. data/lib/bitcoin/gui/connection.rb +2 -0
  29. data/lib/bitcoin/gui/em_gtk.rb +2 -0
  30. data/lib/bitcoin/gui/gui.rb +2 -0
  31. data/lib/bitcoin/gui/helpers.rb +2 -0
  32. data/lib/bitcoin/gui/tree_view.rb +2 -0
  33. data/lib/bitcoin/gui/tx_view.rb +2 -0
  34. data/lib/bitcoin/key.rb +77 -11
  35. data/lib/bitcoin/litecoin.rb +81 -0
  36. data/lib/bitcoin/logger.rb +20 -1
  37. data/lib/bitcoin/namecoin.rb +279 -0
  38. data/lib/bitcoin/network/command_client.rb +7 -6
  39. data/lib/bitcoin/network/command_handler.rb +229 -43
  40. data/lib/bitcoin/network/connection_handler.rb +182 -70
  41. data/lib/bitcoin/network/node.rb +231 -106
  42. data/lib/bitcoin/protocol.rb +44 -23
  43. data/lib/bitcoin/protocol/address.rb +5 -3
  44. data/lib/bitcoin/protocol/alert.rb +3 -4
  45. data/lib/bitcoin/protocol/aux_pow.rb +123 -0
  46. data/lib/bitcoin/protocol/block.rb +98 -18
  47. data/lib/bitcoin/protocol/handler.rb +6 -5
  48. data/lib/bitcoin/protocol/parser.rb +44 -19
  49. data/lib/bitcoin/protocol/tx.rb +105 -52
  50. data/lib/bitcoin/protocol/txin.rb +39 -19
  51. data/lib/bitcoin/protocol/txout.rb +28 -13
  52. data/lib/bitcoin/protocol/version.rb +16 -7
  53. data/lib/bitcoin/script.rb +579 -122
  54. data/lib/bitcoin/storage/{dummy.rb → dummy/dummy_store.rb} +8 -14
  55. data/lib/bitcoin/storage/models.rb +20 -7
  56. data/lib/bitcoin/storage/{sequel_store/sequel_migrations.rb → sequel/migrations.rb} +22 -7
  57. data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +52 -0
  58. data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +50 -0
  59. data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +18 -0
  60. data/lib/bitcoin/storage/sequel/sequel_store.rb +436 -0
  61. data/lib/bitcoin/storage/storage.rb +233 -28
  62. data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +52 -0
  63. data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +18 -0
  64. data/lib/bitcoin/storage/utxo/utxo_store.rb +361 -0
  65. data/lib/bitcoin/validation.rb +369 -0
  66. data/lib/bitcoin/version.rb +1 -1
  67. data/lib/bitcoin/wallet/coinselector.rb +3 -0
  68. data/lib/bitcoin/wallet/keygenerator.rb +3 -1
  69. data/lib/bitcoin/wallet/keystore.rb +6 -2
  70. data/lib/bitcoin/wallet/txdp.rb +6 -4
  71. data/lib/bitcoin/wallet/wallet.rb +54 -16
  72. data/spec/bitcoin/bitcoin_spec.rb +48 -3
  73. data/spec/bitcoin/builder_spec.rb +40 -17
  74. data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
  75. data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
  76. data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
  77. data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
  78. data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
  79. data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
  80. data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
  81. data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
  82. data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
  83. data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
  84. data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
  85. data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
  86. data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
  87. data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
  88. data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
  89. data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  90. data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
  91. data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
  92. data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
  93. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
  94. data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +43 -0
  95. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
  96. data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +67 -0
  97. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  98. data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
  99. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  100. data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
  101. data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
  102. data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
  103. data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
  104. data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
  105. data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
  106. data/spec/bitcoin/key_spec.rb +128 -3
  107. data/spec/bitcoin/namecoin_spec.rb +182 -0
  108. data/spec/bitcoin/network_spec.rb +5 -3
  109. data/spec/bitcoin/node/command_api_spec.rb +376 -0
  110. data/spec/bitcoin/protocol/addr_spec.rb +2 -0
  111. data/spec/bitcoin/protocol/alert_spec.rb +2 -0
  112. data/spec/bitcoin/protocol/aux_pow_spec.rb +44 -0
  113. data/spec/bitcoin/protocol/block_spec.rb +134 -39
  114. data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
  115. data/spec/bitcoin/protocol/inv_spec.rb +10 -8
  116. data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
  117. data/spec/bitcoin/protocol/ping_spec.rb +2 -0
  118. data/spec/bitcoin/protocol/tx_spec.rb +83 -17
  119. data/spec/bitcoin/protocol/version_spec.rb +7 -5
  120. data/spec/bitcoin/script/opcodes_spec.rb +412 -133
  121. data/spec/bitcoin/script/script_spec.rb +112 -13
  122. data/spec/bitcoin/spec_helper.rb +68 -0
  123. data/spec/bitcoin/storage/reorg_spec.rb +199 -0
  124. data/spec/bitcoin/storage/storage_spec.rb +337 -0
  125. data/spec/bitcoin/storage/validation_spec.rb +261 -0
  126. data/spec/bitcoin/wallet/coinselector_spec.rb +10 -7
  127. data/spec/bitcoin/wallet/keygenerator_spec.rb +2 -0
  128. data/spec/bitcoin/wallet/keystore_spec.rb +2 -0
  129. data/spec/bitcoin/wallet/txdp_spec.rb +2 -0
  130. data/spec/bitcoin/wallet/wallet_spec.rb +91 -58
  131. metadata +105 -51
  132. data/lib/bitcoin/storage/sequel.rb +0 -335
  133. data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +0 -27
  134. data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +0 -27
  135. data/spec/bitcoin/reorg_spec.rb +0 -129
  136. data/spec/bitcoin/storage_spec.rb +0 -229
@@ -1,335 +0,0 @@
1
- Bitcoin.require_dependency :sequel, message:
2
- "Note: You will also need an adapter for your database like sqlite3, mysql2, postgresql"
3
- require 'bitcoin/storage/sequel_store/sequel_migrations'
4
-
5
- module Bitcoin::Storage::Backends
6
-
7
- # Storage backend using Sequel to connect to arbitrary SQL databases.
8
- # Inherits from StoreBase and implements its interface.
9
- class SequelStore < StoreBase
10
-
11
-
12
- # possible script types
13
- SCRIPT_TYPES = [:unknown, :pubkey, :hash160, :multisig, :p2sh]
14
-
15
- # sequel database connection
16
- attr_accessor :db
17
-
18
- include Bitcoin::Storage::Backends::SequelMigrations
19
-
20
- # create sequel store with given +config+
21
- def initialize config, *args
22
- @config = config
23
- connect
24
- super config, *args
25
- end
26
-
27
- # connect to database
28
- def connect
29
- {:sqlite => "sqlite3", :postgres => "pg", :mysql => "mysql",
30
- }.each do |adapter, name|
31
- if @config[:db].split(":").first == adapter.to_s
32
- Bitcoin.require_dependency name, gem: name
33
- end
34
- end
35
-
36
- @db = Sequel.connect(@config[:db])
37
- migrate
38
- end
39
-
40
- # reset database; delete all data
41
- def reset
42
- [:blk, :blk_tx, :tx, :txin, :txout].each {|table| @db[table].delete}
43
- end
44
-
45
- # persist given block +blk+ to storage.
46
- def persist_block blk, chain, depth
47
- @db.transaction do
48
- attrs = {
49
- :hash => htb(blk.hash).to_sequel_blob,
50
- :depth => depth,
51
- :chain => chain,
52
- :version => blk.ver,
53
- :prev_hash => blk.prev_block.reverse.to_sequel_blob,
54
- :mrkl_root => blk.mrkl_root.reverse.to_sequel_blob,
55
- :time => blk.time,
56
- :bits => blk.bits,
57
- :nonce => blk.nonce,
58
- :blk_size => blk.to_payload.bytesize,
59
- }
60
- existing = @db[:blk].filter(:hash => htb(blk.hash).to_sequel_blob)
61
- if existing.any?
62
- existing.update attrs
63
- else
64
- block_id = @db[:blk].insert(attrs)
65
- blk.tx.each_with_index do |tx, idx|
66
- tx_id = store_tx(tx)
67
- raise "Error saving tx #{tx.hash} in block #{blk.hash}" unless tx_id
68
- @db[:blk_tx].insert({
69
- :blk_id => block_id,
70
- :tx_id => tx_id,
71
- :idx => idx,
72
- })
73
- end
74
- end
75
- begin
76
- @db[:blk].where(:prev_hash => htb(blk.hash).to_sequel_blob, :chain => ORPHAN).each do |b|
77
- log.debug { "re-org orphan #{hth(b[:hash])}" }
78
- begin
79
- store_block(get_block(hth(b[:hash])))
80
- rescue SystemStackError
81
- EM.defer { store_block(get_block(hth(b[:hash]))) } if EM.reactor_running?
82
- end
83
- end
84
- rescue
85
- p $!
86
- end
87
- log.info { "block #{blk.hash} (#{depth}, #{['main', 'side', 'orphan'][chain]})" }
88
- return depth, chain
89
- end
90
- end
91
-
92
- # update +attrs+ for block with given +hash+.
93
- def update_blocks updates
94
- @db.transaction do
95
- updates.each do |blocks, attrs|
96
- @db[:blk].filter(:hash => blocks.map{|h| htb(h).to_sequel_blob}).update(attrs)
97
- end
98
- end
99
- end
100
-
101
- # store transaction +tx+
102
- def store_tx(tx)
103
- @log.debug { "Storing tx #{tx.hash} (#{tx.to_payload.bytesize} bytes)" }
104
- @db.transaction do
105
- transaction = @db[:tx][:hash => htb(tx.hash).to_sequel_blob]
106
- return transaction[:id] if transaction
107
- tx_id = @db[:tx].insert({
108
- :hash => htb(tx.hash).to_sequel_blob,
109
- :version => tx.ver,
110
- :lock_time => tx.lock_time,
111
- :coinbase => tx.in.size==1 && tx.in[0].coinbase?,
112
- :tx_size => tx.payload.bytesize,
113
- })
114
- tx.in.each_with_index {|i, idx| store_txin(tx_id, i, idx)}
115
- tx.out.each_with_index {|o, idx| store_txout(tx_id, o, idx)}
116
- tx_id
117
- end
118
- rescue
119
- @log.warn { "Error storing tx: #{$!}" }
120
- end
121
-
122
- # store input +txin+
123
- def store_txin(tx_id, txin, idx)
124
- @db[:txin].insert({
125
- :tx_id => tx_id,
126
- :tx_idx => idx,
127
- :script_sig => txin.script_sig.to_sequel_blob,
128
- :prev_out => txin.prev_out.to_sequel_blob,
129
- :prev_out_index => txin.prev_out_index,
130
- :sequence => txin.sequence.unpack("I")[0],
131
- })
132
- end
133
-
134
- # store output +txout+
135
- def store_txout(tx_id, txout, idx)
136
- script = Bitcoin::Script.new(txout.pk_script)
137
- txout_id = @db[:txout].insert({
138
- :tx_id => tx_id,
139
- :tx_idx => idx,
140
- :pk_script => txout.pk_script.to_sequel_blob,
141
- :value => txout.value,
142
- :type => SCRIPT_TYPES.index(script.type)
143
- })
144
- if script.is_hash160? || script.is_pubkey?
145
- store_addr(txout_id, script.get_hash160)
146
- elsif script.is_multisig?
147
- script.get_multisig_pubkeys.map do |pubkey|
148
- store_addr(txout_id, Bitcoin.hash160(pubkey.unpack("H*")[0]))
149
- end
150
- end
151
- txout_id
152
- end
153
-
154
- # store address +hash160+
155
- def store_addr(txout_id, hash160)
156
- addr = @db[:addr][:hash160 => hash160]
157
- addr_id = addr[:id] if addr
158
- addr_id ||= @db[:addr].insert({:hash160 => hash160})
159
- @db[:addr_txout].insert({:addr_id => addr_id, :txout_id => txout_id})
160
- end
161
-
162
- # check if block +blk_hash+ exists
163
- def has_block(blk_hash)
164
- !!@db[:blk].where(:hash => htb(blk_hash).to_sequel_blob).get(1)
165
- end
166
-
167
- # check if transaction +tx_hash+ exists
168
- def has_tx(tx_hash)
169
- !!@db[:tx].where(:hash => htb(tx_hash).to_sequel_blob).get(1)
170
- end
171
-
172
- # get head block (highest block from the MAIN chain)
173
- def get_head
174
- wrap_block(@db[:blk].filter(:chain => MAIN).order(:depth).last)
175
- end
176
-
177
- # get depth of MAIN chain
178
- def get_depth
179
- return -1 unless get_head
180
- @db[:blk][:hash => htb(get_head.hash).to_sequel_blob][:depth]
181
- end
182
-
183
- # get block for given +blk_hash+
184
- def get_block(blk_hash)
185
- wrap_block(@db[:blk][:hash => htb(blk_hash).to_sequel_blob])
186
- end
187
-
188
- # get block by given +depth+
189
- def get_block_by_depth(depth)
190
- wrap_block(@db[:blk][:depth => depth, :chain => MAIN])
191
- end
192
-
193
- # get block by given +prev_hash+
194
- def get_block_by_prev_hash(prev_hash)
195
- wrap_block(@db[:blk][:prev_hash => htb(prev_hash).to_sequel_blob])
196
- end
197
-
198
- # get block by given +tx_hash+
199
- def get_block_by_tx(tx_hash)
200
- tx = @db[:tx][:hash => htb(tx_hash).to_sequel_blob]
201
- return nil unless tx
202
- parent = @db[:blk_tx][:tx_id => tx[:id]]
203
- return nil unless parent
204
- wrap_block(@db[:blk][:id => parent[:blk_id]])
205
- end
206
-
207
- # get block by given +id+
208
- def get_block_by_id(block_id)
209
- wrap_block(@db[:blk][:id => block_id])
210
- end
211
-
212
- # get transaction for given +tx_hash+
213
- def get_tx(tx_hash)
214
- wrap_tx(@db[:tx][:hash => htb(tx_hash).to_sequel_blob])
215
- end
216
-
217
- # get transaction by given +tx_id+
218
- def get_tx_by_id(tx_id)
219
- wrap_tx(@db[:tx][:id => tx_id])
220
- end
221
-
222
- # get corresponding Models::TxIn for the txout in transaction
223
- # +tx_hash+ with index +txout_idx+
224
- def get_txin_for_txout(tx_hash, txout_idx)
225
- tx_hash = htb(tx_hash).reverse.to_sequel_blob
226
- wrap_txin(@db[:txin][:prev_out => tx_hash, :prev_out_index => txout_idx])
227
- end
228
-
229
- # get corresponding Models::TxOut for +txin+
230
- def get_txout_for_txin(txin)
231
- tx = @db[:tx][:hash => txin.prev_out.reverse.to_sequel_blob]
232
- return nil unless tx
233
- wrap_txout(@db[:txout][:tx_idx => txin.prev_out_index, :tx_id => tx[:id]])
234
- end
235
-
236
- # get all Models::TxOut matching given +script+
237
- def get_txouts_for_pk_script(script)
238
- txouts = @db[:txout].filter(:pk_script => script.to_sequel_blob).order(:id)
239
- txouts.map{|txout| wrap_txout(txout)}
240
- end
241
-
242
- # get all Models::TxOut matching given +hash160+
243
- def get_txouts_for_hash160(hash160, unconfirmed = false)
244
- addr = @db[:addr][:hash160 => hash160]
245
- return [] unless addr
246
- txouts = @db[:addr_txout].where(:addr_id => addr[:id])
247
- .map{|t| @db[:txout][:id => t[:txout_id]] }
248
- .map{|o| wrap_txout(o) }
249
- unless unconfirmed
250
- txouts.select!{|o| o.get_tx.get_block.chain == MAIN rescue false }
251
- end
252
- txouts
253
- end
254
-
255
- # get all unconfirmed Models::TxOut
256
- def get_unconfirmed_tx
257
- @db[:unconfirmed].map{|t| wrap_tx(t)}
258
- end
259
-
260
- # wrap given +block+ into Models::Block
261
- def wrap_block(block)
262
- return nil unless block
263
-
264
- data = {:id => block[:id], :depth => block[:depth], :chain => block[:chain]}
265
- blk = Bitcoin::Storage::Models::Block.new(self, data)
266
-
267
- blk.ver = block[:version]
268
- blk.prev_block = block[:prev_hash].reverse
269
- blk.mrkl_root = block[:mrkl_root].reverse
270
- blk.time = block[:time].to_i
271
- blk.bits = block[:bits]
272
- blk.nonce = block[:nonce]
273
- parents = db[:blk_tx].filter(:blk_id => block[:id])
274
- .order(:idx) rescue []
275
- parents.each do |parent|
276
- transaction = db[:tx][:id => parent[:tx_id]]
277
- blk.tx << wrap_tx(transaction)
278
- end
279
-
280
- blk.recalc_block_hash
281
- blk
282
- end
283
-
284
- # wrap given +transaction+ into Models::Transaction
285
- def wrap_tx(transaction)
286
- return nil unless transaction
287
-
288
- parents = @db[:blk_tx].where(:tx_id => transaction[:id])
289
- parent = parents.map{|m|@db[:blk][:id => m[:blk_id]]}.sort_by {|b| b[:chain]}.first
290
- block_id = parent ? parent[:id] : nil
291
- data = {:id => transaction[:id], :blk_id => block_id}
292
- tx = Bitcoin::Storage::Models::Tx.new(self, data)
293
-
294
- inputs = db[:txin].filter(:tx_id => transaction[:id]).order(:tx_idx)
295
- inputs.each { |i| tx.add_in(wrap_txin(i)) }
296
-
297
- outputs = db[:txout].filter(:tx_id => transaction[:id]).order(:tx_idx)
298
- outputs.each { |o| tx.add_out(wrap_txout(o)) }
299
- tx.ver = transaction[:version]
300
- tx.lock_time = transaction[:lock_time]
301
- tx.hash = tx.hash_from_payload(tx.to_payload)
302
- tx
303
- end
304
-
305
- # wrap given +input+ into Models::TxIn
306
- def wrap_txin(input)
307
- return nil unless input
308
- data = {:id => input[:id], :tx_id => input[:tx_id], :tx_idx => input[:tx_idx]}
309
- txin = Bitcoin::Storage::Models::TxIn.new(self, data)
310
- txin.prev_out = input[:prev_out]
311
- txin.prev_out_index = input[:prev_out_index]
312
- txin.script_sig_length = input[:script_sig].bytesize
313
- txin.script_sig = input[:script_sig]
314
- txin.sequence = [input[:sequence]].pack("I")
315
- txin
316
- end
317
-
318
- # wrap given +output+ into Models::TxOut
319
- def wrap_txout(output)
320
- return nil unless output
321
- data = {:id => output[:id], :tx_id => output[:tx_id], :tx_idx => output[:tx_idx],
322
- :hash160 => output[:hash160], :type => SCRIPT_TYPES[output[:type]]}
323
- txout = Bitcoin::Storage::Models::TxOut.new(self, data)
324
- txout.value = output[:value]
325
- txout.pk_script = output[:pk_script]
326
- txout
327
- end
328
-
329
-
330
- def hth(bin); bin.unpack("H*")[0]; end
331
- def htb(hex); [hex].pack("H*"); end
332
-
333
- end
334
-
335
- end
@@ -1,27 +0,0 @@
1
- {
2
- "hash":"0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd",
3
- "ver":1,
4
- "vin_sz":1,
5
- "vout_sz":2,
6
- "lock_time":0,
7
- "size":224,
8
- "in":[
9
- {
10
- "prev_out":{
11
- "hash":"477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590",
12
- "n":0
13
- },
14
- "scriptSig":"30450220668828280473923647f2fb99450578a18f81e92358d94c933b7033b4370448b8022100cfbce6723163c907b3b86777f0698cc29ea5f89d0fce657a3894afcb1c717da501 033be10bdc7ff38235cf469449147636c4e0e49aacdd0a25af4109cbebd361e0d2"
15
- }
16
- ],
17
- "out":[
18
- {
19
- "value":"0.02900000",
20
- "scriptPubKey":"OP_DUP OP_HASH160 2758fcf332b5df477ec6d877d3b72526b827202b OP_EQUALVERIFY OP_CHECKSIG"
21
- },
22
- {
23
- "value":"0.01000000",
24
- "scriptPubKey":"51c387bb5c66d1e9d4d054fd96d0844eecf3b664 OP_NOP2 OP_DROP"
25
- }
26
- ]
27
- }
@@ -1,27 +0,0 @@
1
- {
2
- "hash":"477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590",
3
- "ver":1,
4
- "vin_sz":1,
5
- "vout_sz":2,
6
- "lock_time":0,
7
- "size":224,
8
- "in":[
9
- {
10
- "prev_out":{
11
- "hash":"458b9f6cf2d931d72e246d5ca3d7773069430322a0a1a41653d23a5a3cc3e7ea",
12
- "n":1
13
- },
14
- "scriptSig":"304502205b910ff27919bb4b81847e17e19848a8148373b5d84856e8a0798395c1a4df6e022100a9300a11b37b52997726dab17851914151bd647ca053d60a013b8e0ad42d1c6e01 02b2e1e38d1b15170212a852f68045979d790814a139ed57bffba3763f75e18808"
15
- }
16
- ],
17
- "out":[
18
- {
19
- "value":"0.03950000",
20
- "scriptPubKey":"OP_DUP OP_HASH160 c39c8d989dfdd7fde0ee80be36113c5abcefcb9c OP_EQUALVERIFY OP_CHECKSIG"
21
- },
22
- {
23
- "value":"0.01000000",
24
- "scriptPubKey":"64d63d835705618da2111ca3194f22d067187cf2 OP_NOP2 OP_DROP"
25
- }
26
- ]
27
- }
@@ -1,129 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- include Bitcoin::Builder
4
-
5
- describe "reorg" do
6
-
7
- def create_block prev, store = true
8
- block = blk do |b|
9
- b.prev_block prev
10
- b.tx do |t|
11
- t.input {|i| i.coinbase }
12
- t.output do |o|
13
- o.value 5000000000
14
- o.script {|s| s.type :address; s.recipient Bitcoin::Key.generate.addr }
15
- end
16
- end
17
- end
18
- @store.store_block(block) if store
19
- block
20
- end
21
-
22
- def balance addr
23
- @store.get_balance(Bitcoin.hash160_from_address(addr))
24
- end
25
-
26
- before do
27
- Bitcoin.network = :testnet
28
- @store = Bitcoin::Storage.sequel(:db => "sqlite:/")
29
- @store.log.level = :warn
30
- @block0 = Bitcoin::Protocol::Block.new(fixtures_file('testnet/block_0.bin'))
31
- @store.store_block(@block0)
32
- end
33
-
34
- it "should reorg a single side block" do
35
- @store.get_head.should == @block0
36
-
37
- block1 = create_block @block0.hash
38
- @store.get_head.should == block1
39
-
40
- block2_0 = create_block block1.hash
41
- @store.get_head.should == block2_0
42
-
43
- block2_1 = create_block block1.hash
44
- @store.get_head.should == block2_0
45
-
46
- block3 = create_block block2_1.hash
47
- @store.get_head.should == block3
48
- @store.get_block_by_depth(2).hash.should == block2_1.hash
49
- end
50
-
51
- it "should reorg two side blocks" do
52
- block1 = create_block @block0.hash
53
- @store.get_head.should == block1
54
-
55
- block2_0 = create_block block1.hash
56
- @store.get_head.should == block2_0
57
-
58
- block2_1 = create_block block1.hash
59
- @store.get_head.should == block2_0
60
-
61
- block3_1 = create_block block2_1.hash
62
- @store.get_head.should == block3_1
63
-
64
- block3_0 = create_block block2_0.hash
65
- @store.get_head.should == block3_1
66
-
67
- block4 = create_block block3_0.hash
68
- @store.get_head.should == block4
69
- end
70
-
71
- it "should reconnect orphans" do
72
- blocks = [@block0]
73
- 3.times { blocks << create_block(blocks.last.hash, false) }
74
-
75
- {
76
- [0, 1, 2, 3] => [0, 1, 2, 3],
77
- [0, 1, 3, 2] => [0, 1, 1, 3],
78
- [0, 3, 2, 1] => [0, 0, 0, 3],
79
- [0, 3, 1, 2] => [0, 0, 1, 3],
80
- [0, 2, 3, 1] => [0, 0, 0, 3],
81
- }.each do |order, result|
82
- @store.reset
83
- order.each_with_index do |n, i|
84
- @store.store_block(blocks[n])
85
- @store.get_head.should == blocks[result[i]]
86
- end
87
- end
88
-
89
- i = 3; (0..i).to_a.permutation.each do |order|
90
- @store.reset
91
- order.each {|n| @store.store_block(blocks[n]) }
92
- @store.get_head.should == blocks[i]
93
- end
94
- end
95
-
96
- it "should handle existing blocks" do
97
- Bitcoin.network = :testnet
98
- blocks = [@block0]
99
- 3.times { blocks << create_block(blocks.last.hash, false) }
100
- 3.times do
101
- @store.store_block(blocks[1]).should == [1, 0]
102
- @store.store_block(blocks[2]).should == [2, 0]
103
- @store.get_head.should == blocks[2]
104
- end
105
- end
106
-
107
- # see https://bitcointalk.org/index.php?topic=46370.0
108
- it "should pass reorg unit tests" do
109
- Bitcoin.network = :bitcoin
110
- @store.import "./spec/bitcoin/fixtures/reorg/blk_0_to_4.dat"
111
- @store.get_depth.should == 4
112
- @store.get_head.hash.should =~ /000000002f264d65040/
113
- balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 10000000000
114
- balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 0
115
- balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 5000000000
116
- balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 10000000000
117
- @store.import "./spec/bitcoin/fixtures/reorg/blk_3A.dat"
118
- @store.import "./spec/bitcoin/fixtures/reorg/blk_4A.dat"
119
- @store.get_head.hash.should =~ /000000002f264d65040/
120
- @store.import "./spec/bitcoin/fixtures/reorg/blk_5A.dat"
121
- @store.get_depth.should == 5
122
- @store.get_head.hash.should =~ /00000000195f85184e7/
123
- balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 15000000000
124
- balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 1000000000
125
- balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 0
126
- balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 14000000000
127
- end
128
-
129
- end